mirror of
https://github.com/nickmqb/wyre.git
synced 2025-12-06 02:30:42 -08:00
Fix bugs, add cast builtin, bump version
This commit is contained in:
parent
0aeb7777a5
commit
d7114cf681
10 changed files with 180 additions and 59 deletions
|
|
@ -103,10 +103,10 @@ parseArgs(parser CommandLineArgsParser, isCompiler bool) {
|
|||
if args.outputPath == "" && isCompiler {
|
||||
parser.expected("--output [path]")
|
||||
}
|
||||
if !hasIndent && isCompiler {
|
||||
if !hasIndent {
|
||||
parser.expected("--indent [number]")
|
||||
}
|
||||
if !hasMaxErrors {
|
||||
if !hasMaxErrors && isCompiler {
|
||||
parser.expected("--max-errors [number]")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ CallExpression struct #RefType {
|
|||
BuiltinCall enum {
|
||||
none
|
||||
rep
|
||||
cast_
|
||||
slice
|
||||
chunk
|
||||
swizzle
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ EmulatorState struct #RefType {
|
|||
|
||||
tape List<Instruction>
|
||||
resetProgram List<Instruction>
|
||||
stepProgram List<Instruction>
|
||||
propagateProgram List<Instruction>
|
||||
updateProgram List<Instruction>
|
||||
|
||||
stack List<Value>
|
||||
cycle long
|
||||
|
|
@ -68,7 +69,8 @@ Emulator {
|
|||
evalCtxField: -1,
|
||||
evalCtxOutput: -1,
|
||||
resetProgram: new List<Instruction>{},
|
||||
stepProgram: new List<Instruction>{},
|
||||
propagateProgram: new List<Instruction>{},
|
||||
updateProgram: new List<Instruction>{},
|
||||
stack: new List<Value>{},
|
||||
cycle: -1,
|
||||
}
|
||||
|
|
@ -91,12 +93,14 @@ Emulator {
|
|||
}
|
||||
|
||||
if s.comp.flags & CompilationFlags.simulate != 0 {
|
||||
s.tape = s.stepProgram
|
||||
s.tape = s.propagateProgram
|
||||
for si in s.evalOrder {
|
||||
if !s.infos[si].isStatic && !s.infos[si].isReg {
|
||||
EmulatorStep.slot(s, si)
|
||||
}
|
||||
}
|
||||
|
||||
s.tape = s.updateProgram
|
||||
for mi in s.moduleInstances {
|
||||
EmulatorStep.module(s, mi)
|
||||
assert(s.evalCtxField == -1 && s.evalCtxOutput == -1)
|
||||
|
|
@ -113,7 +117,10 @@ Emulator {
|
|||
|
||||
step(s EmulatorState, clk string, val ulong) {
|
||||
EmulatorRunner.setInput(s, s.moduleInstances[0], clk, val)
|
||||
EmulatorRunner.run(s, s.stepProgram)
|
||||
EmulatorRunner.run(s, s.propagateProgram)
|
||||
EmulatorRunner.run(s, s.updateProgram)
|
||||
Emulator.commitValues(s)
|
||||
EmulatorRunner.run(s, s.propagateProgram)
|
||||
}
|
||||
|
||||
commitValues(s EmulatorState) {
|
||||
|
|
@ -142,7 +149,7 @@ EmulatorStep {
|
|||
clock(s EmulatorState, st ClockStatement) {
|
||||
token(s, st.name) // TODO: does not actually check edges, just looks at current state
|
||||
if st.keyword.value != "posedge" {
|
||||
emit(s, Opcode.invert)
|
||||
emit(s, Opcode.not)
|
||||
}
|
||||
pc := emit(s, Opcode.jumpIfZero)
|
||||
block(s, st.body)
|
||||
|
|
@ -421,6 +428,9 @@ EmulatorStep {
|
|||
if e.builtin == BuiltinCall.rep {
|
||||
rep(s, e)
|
||||
return
|
||||
} else if e.builtin == BuiltinCall.cast_ {
|
||||
cast_(s, e)
|
||||
return
|
||||
} else if e.builtin == BuiltinCall.slice {
|
||||
slice(s, e)
|
||||
return
|
||||
|
|
@ -452,13 +462,36 @@ EmulatorStep {
|
|||
}
|
||||
}
|
||||
|
||||
cast_(s EmulatorState, e CallExpression) {
|
||||
assert(s.evalCtxField == -1 && s.evalCtxOutput == -1)
|
||||
fromTag := s.typeMap.get(e.args[0].expr)
|
||||
tag := s.typeMap.get(e.args[1].expr)
|
||||
assert(fromTag.kind == TagKind.number)
|
||||
assert(tag.kind == TagKind.number && tag.q > 0)
|
||||
expression(s, e.args[0].expr)
|
||||
if fromTag.q == 0 {
|
||||
if tag.q <= 64 {
|
||||
mask(s, tag)
|
||||
}
|
||||
} else if tag.q < fromTag.q {
|
||||
if tag.q <= 64 {
|
||||
if fromTag.q > 64 {
|
||||
emit(s, Opcode.toULong)
|
||||
}
|
||||
mask(s, tag)
|
||||
} else {
|
||||
abandon()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slice(s EmulatorState, e CallExpression) {
|
||||
assert(s.evalCtxField == -1 && s.evalCtxOutput == -1)
|
||||
dest := s.typeMap.get(e.args[0].expr)
|
||||
target := s.typeMap.get(e.args[0].expr)
|
||||
expression(s, e.args[0].expr)
|
||||
expression(s, e.args[1].expr)
|
||||
expression(s, e.args[2].expr)
|
||||
emiti(s, Opcode.slice, TypeChecker.unpackWidth(dest))
|
||||
emiti(s, Opcode.slice, TypeChecker.unpackWidth(target))
|
||||
}
|
||||
|
||||
assignSlice(s EmulatorState, st AssignStatement, e CallExpression, si int) {
|
||||
|
|
|
|||
|
|
@ -252,13 +252,18 @@ EmulatorOrderCalculator {
|
|||
block(s EmulatorState, st Block) {
|
||||
for n in st.contents {
|
||||
match n {
|
||||
ClockStatement: block(s, n.body)
|
||||
ClockStatement: clock(s, n)
|
||||
IfStatement: if_(s, n)
|
||||
AssignStatement: assign(s, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clock(s EmulatorState, st ClockStatement) {
|
||||
token(s, st.name)
|
||||
block(s, st.body)
|
||||
}
|
||||
|
||||
if_(s EmulatorState, st IfStatement) {
|
||||
expression(s, st.expr)
|
||||
block(s, st.ifBody)
|
||||
|
|
@ -328,8 +333,9 @@ EmulatorOrderCalculator {
|
|||
abandon()
|
||||
}
|
||||
} else if st.nameExpr.is(CallExpression) {
|
||||
call := st.nameExpr.as(CallExpression)
|
||||
if call.builtin == BuiltinCall.slice {
|
||||
callExpr := st.nameExpr.as(CallExpression)
|
||||
if callExpr.builtin == BuiltinCall.slice {
|
||||
call(s, callExpr)
|
||||
expression(s, st.expr)
|
||||
} else {
|
||||
abandon()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//tab_size=4
|
||||
:compilerVersion = "0.1.1"
|
||||
:compilerVersion = "0.1.2"
|
||||
|
||||
ParseCommaListState enum {
|
||||
start
|
||||
|
|
@ -671,6 +671,8 @@ Parser {
|
|||
name := lhs.as(Token).value
|
||||
if name == "rep" {
|
||||
node.builtin = BuiltinCall.rep
|
||||
} else if name == "cast" {
|
||||
node.builtin = BuiltinCall.cast_
|
||||
} else if name == "slice" {
|
||||
node.builtin = BuiltinCall.slice
|
||||
} else if name == "chunk" {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Opcode enum {
|
|||
discard
|
||||
neg
|
||||
invert
|
||||
not
|
||||
add
|
||||
sub
|
||||
and
|
||||
|
|
@ -30,6 +31,7 @@ Opcode enum {
|
|||
slice
|
||||
storeSlice
|
||||
swizzle
|
||||
toULong
|
||||
|
||||
toString(op Opcode) {
|
||||
if op == Opcode.push {
|
||||
|
|
@ -60,6 +62,8 @@ Opcode enum {
|
|||
return "neg"
|
||||
} else if op == Opcode.invert {
|
||||
return "invert"
|
||||
} else if op == Opcode.not {
|
||||
return "not"
|
||||
} else if op == Opcode.add {
|
||||
return "add"
|
||||
} else if op == Opcode.sub {
|
||||
|
|
@ -94,6 +98,8 @@ Opcode enum {
|
|||
return "storeSlice"
|
||||
} else if op == Opcode.swizzle {
|
||||
return "swizzle"
|
||||
} else if op == Opcode.toULong {
|
||||
return "toULong"
|
||||
} else {
|
||||
return "?"
|
||||
}
|
||||
|
|
@ -147,6 +153,8 @@ EmulatorRunner {
|
|||
stack[top].z = -unpack(stack[top])
|
||||
} else if ins.op == Opcode.invert {
|
||||
stack[top].z = ~unpack(stack[top])
|
||||
} else if ins.op == Opcode.not {
|
||||
stack[top].z = unpack(stack[top]) == 0 ? 1_uL : 0
|
||||
} else if ins.op == Opcode.add {
|
||||
binaryOperator(s, stack, unpack(stack[lhs]) + unpack(stack[top]))
|
||||
} else if ins.op == Opcode.sub {
|
||||
|
|
@ -186,6 +194,8 @@ EmulatorRunner {
|
|||
value := swizzle(s, stack[stack.count - 5], cast(unpack(stack[stack.count - 4]), int), cast(unpack(stack[stack.count - 3]), int), cast(unpack(stack[lhs]), int), cast(unpack(stack[top]), int))
|
||||
stack.setCountChecked(stack.count - 5)
|
||||
stack.add(value)
|
||||
} else if ins.op == Opcode.toULong {
|
||||
stack[top] = Value { z: unpackAsULong(stack[top]), kind: ValueKind.ulong_ }
|
||||
} else {
|
||||
abandon()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ TypeChecker {
|
|||
s.isStaticExpr = false
|
||||
if etr.tag.kind != TagKind.unknown {
|
||||
if def.type != null {
|
||||
if canAssign(s, etr.tag, etr.value, dt) {
|
||||
if canAssign_andUpgrade(s, etr.tag, etr.value, def.expr, dt) {
|
||||
if etr.value.kind != ValueKind.none {
|
||||
// OK
|
||||
} else {
|
||||
|
|
@ -200,7 +200,7 @@ TypeChecker {
|
|||
s.errors.add(Error.at(s.unit, def.type.span, "Field type cannot be larger than $64"))
|
||||
}
|
||||
} else {
|
||||
expectedFixedNumber(s, def.type)
|
||||
expectedFixedNumberType(s, def.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -313,6 +313,17 @@ TypeChecker {
|
|||
}
|
||||
|
||||
assign(s TypeCheckerState, st AssignStatement) {
|
||||
assignSym(s, st)
|
||||
if st.flags & AssignFlags.regUpdate != 0 {
|
||||
if s.inClock {
|
||||
// OK
|
||||
} else {
|
||||
s.errors.add(Error.at(s.unit, st.outKeyword != null ? st.outKeyword.span : RangeFinder.find(st.nameExpr), "Statement must be placed inside clock statement"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assignSym(s TypeCheckerState, st AssignStatement) {
|
||||
if st.flags & AssignFlags.typeCheckDone != 0 {
|
||||
return
|
||||
}
|
||||
|
|
@ -335,11 +346,11 @@ TypeChecker {
|
|||
// OK
|
||||
} else if st.flags & AssignFlags.typeCheckStarted == 0 {
|
||||
prev := pushContext(s, st.module.unit, st.module)
|
||||
assign(s, st)
|
||||
assignSym(s, st)
|
||||
restoreContext(s, prev)
|
||||
} else {
|
||||
kind := (st.flags & AssignFlags.reg != 0) ? "register" : "wire"
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(reference), format("Recursive reference to {}", kind)))
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(reference), format("Type of {} cannot be inferred due to recursive reference, please specify the type explicity", kind)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,11 +384,7 @@ TypeChecker {
|
|||
} else if st.op.value == "<=" {
|
||||
st.flags |= AssignFlags.regUpdate
|
||||
if st.expr != null {
|
||||
if s.inClock {
|
||||
// OK
|
||||
} else {
|
||||
s.errors.add(Error.at(s.unit, st.outKeyword != null ? st.outKeyword.span : RangeFinder.find(st.nameExpr), "Statement must be placed inside clock statement"))
|
||||
}
|
||||
} else {
|
||||
s.errors.add(Error.atIndex(s.unit, st.op.span.to, "Expected: expression"))
|
||||
}
|
||||
|
|
@ -393,17 +400,15 @@ TypeChecker {
|
|||
if st.expr != null {
|
||||
if st.type != null {
|
||||
tag := typename(s, st, st.type)
|
||||
if st.flags & AssignFlags.regUpdate != 0 {
|
||||
// Mark as done so reg can be referenced by expression. This is fine as we have just determined the type of the register.
|
||||
st.flags |= AssignFlags.typeCheckDone
|
||||
}
|
||||
s.isStaticExpr = st.flags & AssignFlags.regUpdate == 0
|
||||
rhs := expressionWithGap(s, st.expr, st.type != null, tag)
|
||||
s.isStaticExpr = false
|
||||
if st.op != null && tag.isValid() {
|
||||
if isFixedNumberOrStruct(tag) {
|
||||
if rhs.tag.isValid() {
|
||||
if canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if canAssign_andUpgrade(s, rhs.tag, rhs.value, st.expr, tag) {
|
||||
s.module.numRegSlots += numSlots(s.comp, tag)
|
||||
} else {
|
||||
badAssign(s, st.op, rhs.tag, tag)
|
||||
|
|
@ -488,12 +493,14 @@ TypeChecker {
|
|||
if st.expr != null {
|
||||
if st.type != null {
|
||||
tag := typename(s, st, st.type)
|
||||
// Mark as done so reg can be referenced by expression. This is fine as we have just determined the type of the wire.
|
||||
st.flags |= AssignFlags.typeCheckDone
|
||||
s.isStaticExpr = st.flags & AssignFlags.static != 0
|
||||
rhs := expressionWithGap(s, st.expr, st.type != null, tag)
|
||||
s.isStaticExpr = false
|
||||
if st.op != null && tag.isValid() {
|
||||
if isFixedNumberOrStruct(tag) {
|
||||
if canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if canAssign_andUpgrade(s, rhs.tag, rhs.value, st.expr, tag) {
|
||||
// OK
|
||||
} else {
|
||||
badAssign(s, st.op, rhs.tag, tag)
|
||||
|
|
@ -547,10 +554,6 @@ TypeChecker {
|
|||
}
|
||||
|
||||
regUpdate(s TypeCheckerState, st AssignStatement) {
|
||||
if !s.inClock {
|
||||
s.errors.add(Error.at(s.unit, st.outKeyword != null ? st.outKeyword.span : RangeFinder.find(st.nameExpr), "Statement must be placed inside clock statement"))
|
||||
}
|
||||
|
||||
if s.module.blackboxKeyword != null {
|
||||
statementNotAllowedInsideBlackbox(s, st.outKeyword != null ? st.outKeyword : st.nameExpr)
|
||||
}
|
||||
|
|
@ -587,7 +590,7 @@ TypeChecker {
|
|||
}
|
||||
if st.expr != null {
|
||||
rhs := expressionWithGap(s, st.expr, true, tag)
|
||||
if canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if canAssign_andUpgrade(s, rhs.tag, rhs.value, st.expr, tag) {
|
||||
// OK
|
||||
} else {
|
||||
badAssign(s, st.op, rhs.tag, tag)
|
||||
|
|
@ -629,7 +632,7 @@ TypeChecker {
|
|||
}
|
||||
if st.expr != null {
|
||||
rhs := expressionWithGap(s, st.expr, true, tag)
|
||||
if canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if canAssign_andUpgrade(s, rhs.tag, rhs.value, st.expr, tag) {
|
||||
// OK
|
||||
} else {
|
||||
badAssign(s, st.op, rhs.tag, tag)
|
||||
|
|
@ -826,13 +829,13 @@ TypeChecker {
|
|||
unsupportedBinaryOp(s, e.op, lhs.tag, rhs.tag)
|
||||
} else if lhs.tag.q > 0 || rhs.tag.q > 0 {
|
||||
if lhs.tag.q == 0 {
|
||||
if canConvertFreeConst(s, lhs.value, rhs.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, lhs.value, e.lhs, rhs.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: rhs.tag.q }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.lhs), rhs.tag)
|
||||
}
|
||||
} else if rhs.tag.q == 0 {
|
||||
if canConvertFreeConst(s, rhs.value, lhs.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, rhs.value, e.rhs, lhs.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: lhs.tag.q }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.rhs), lhs.tag)
|
||||
|
|
@ -874,13 +877,13 @@ TypeChecker {
|
|||
unsupportedBinaryOp(s, e.op, lhs.tag, rhs.tag)
|
||||
} else if lhs.tag.q > 0 || rhs.tag.q > 0 {
|
||||
if lhs.tag.q == 0 {
|
||||
if canConvertFreeConst(s, lhs.value, rhs.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, lhs.value, e.lhs, rhs.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: 1 }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.lhs), rhs.tag)
|
||||
}
|
||||
} else if rhs.tag.q == 0 {
|
||||
if canConvertFreeConst(s, rhs.value, lhs.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, rhs.value, e.rhs, lhs.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: 1 }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.rhs), lhs.tag)
|
||||
|
|
@ -971,14 +974,14 @@ TypeChecker {
|
|||
fe := e.falseExpr != null ? expressionContinueGap(s, e.falseExpr) : TypeCheckResult{}
|
||||
if s.gap && s.gapTag.kind == TagKind.number && s.gapTag.q > 0 {
|
||||
if te.tag.isValid() {
|
||||
if canAssign(s, te.tag, te.value, s.gapTag) {
|
||||
if canAssign_andUpgrade(s, te.tag, te.value, e.trueExpr, s.gapTag) {
|
||||
// OK
|
||||
} else {
|
||||
badConversion(s, e.trueExpr, te.tag, s.gapTag)
|
||||
}
|
||||
}
|
||||
if fe.tag.isValid() {
|
||||
if canAssign(s, fe.tag, fe.value, s.gapTag) {
|
||||
if canAssign_andUpgrade(s, fe.tag, fe.value, e.falseExpr, s.gapTag) {
|
||||
// OK
|
||||
} else {
|
||||
badConversion(s, e.falseExpr, fe.tag, s.gapTag)
|
||||
|
|
@ -990,13 +993,13 @@ TypeChecker {
|
|||
if te.tag.kind == TagKind.number && fe.tag.kind == TagKind.number {
|
||||
if te.tag.q > 0 || fe.tag.q > 0 {
|
||||
if te.tag.q == 0 {
|
||||
if canConvertFreeConst(s, te.value, fe.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, te.value, e.trueExpr, fe.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: fe.tag.q }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.trueExpr), fe.tag)
|
||||
}
|
||||
} else if fe.tag.q == 0 {
|
||||
if canConvertFreeConst(s, fe.value, te.tag.q) {
|
||||
if canConvertFreeConst_andUpgrade(s, fe.value, e.falseExpr, te.tag) {
|
||||
result.tag = Tag { kind: TagKind.number, q: te.tag.q }
|
||||
} else {
|
||||
badBinaryOperandConversion(s, RangeFinder.find(e.falseExpr), te.tag)
|
||||
|
|
@ -1073,7 +1076,7 @@ TypeChecker {
|
|||
if vex.tag.isValid() {
|
||||
if vex.tag.kind == TagKind.number && vex.value.kind == ValueKind.ulong_ {
|
||||
if condValid {
|
||||
if canAssign(s, vex.tag, vex.value, target.tag) {
|
||||
if canAssign_andUpgrade(s, vex.tag, vex.value, c.valueExpr, target.tag) {
|
||||
// OK
|
||||
} else {
|
||||
badConstConversion(s, c.valueExpr, vex.tag, target.tag)
|
||||
|
|
@ -1203,6 +1206,8 @@ TypeChecker {
|
|||
call(s TypeCheckerState, e CallExpression) {
|
||||
if e.builtin == BuiltinCall.rep {
|
||||
return rep(s, e)
|
||||
} else if e.builtin == BuiltinCall.cast_ {
|
||||
return cast_(s, e)
|
||||
} else if e.builtin == BuiltinCall.slice {
|
||||
return slice(s, e)
|
||||
} else if e.builtin == BuiltinCall.chunk {
|
||||
|
|
@ -1273,7 +1278,7 @@ TypeChecker {
|
|||
rhs := expressionWithGap(s, arg.expr, true, tag)
|
||||
s.allowDontCare = false
|
||||
s.isStaticExpr = false
|
||||
if !canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if !canAssign_andUpgrade(s, rhs.tag, rhs.value, arg.expr, tag) {
|
||||
badAssign(s, arg.colon, rhs.tag, tag)
|
||||
}
|
||||
if arg.name == null {
|
||||
|
|
@ -1344,7 +1349,7 @@ TypeChecker {
|
|||
|
||||
if arg.expr != null {
|
||||
rhs := expressionWithGap(s, arg.expr, true, tag)
|
||||
if !canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if !canAssign_andUpgrade(s, rhs.tag, rhs.value, arg.expr, tag) {
|
||||
badAssign(s, arg.colon, rhs.tag, tag)
|
||||
}
|
||||
if arg.name == null {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,30 @@ TypeChecker {
|
|||
return result
|
||||
}
|
||||
|
||||
cast_(s TypeCheckerState, e CallExpression) {
|
||||
if s.isStaticExpr {
|
||||
// OK
|
||||
} else if s.comp.flags & CompilationFlags.simulate == 0 {
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(e.target), "cast() can only be used in static initializer or in simulator"))
|
||||
}
|
||||
builtinArgs(s, e, 2)
|
||||
target := numberArg(s, e, 0)
|
||||
typeArg := fixedNumericTypeArg(s, e, 1)
|
||||
result := TypeCheckResult{}
|
||||
if target.tag.isValid() && typeArg.tag.isValid() {
|
||||
result.tag = typeArg.tag
|
||||
if typeArg.tag.q >= target.tag.q || typeArg.tag.q <= 64 {
|
||||
// OK
|
||||
} else {
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(e), "Unsupported cast; downcast not allowed for expressions larger than $64"))
|
||||
}
|
||||
if typeArg.tag.q >= target.tag.q && target.tag.q > 0 {
|
||||
result.value = target.value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
slice(s TypeCheckerState, e CallExpression) {
|
||||
if s.module == null {
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(e.target), "Cannot use slice() in constant initializer"))
|
||||
|
|
@ -108,7 +132,7 @@ TypeChecker {
|
|||
}
|
||||
if st.expr != null {
|
||||
rhs := expressionWithGap(s, st.expr, true, tag)
|
||||
if canAssign(s, rhs.tag, rhs.value, tag) {
|
||||
if canAssign_andUpgrade(s, rhs.tag, rhs.value, st.expr, tag) {
|
||||
// OK
|
||||
} else {
|
||||
badAssign(s, st.op, rhs.tag, tag)
|
||||
|
|
@ -259,4 +283,30 @@ TypeChecker {
|
|||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
fixedNumericTypeArg(s TypeCheckerState, e CallExpression, index int) {
|
||||
if index >= e.args.count {
|
||||
return TypeCheckResult{}
|
||||
}
|
||||
arg := e.args[index]
|
||||
if arg.expr == null {
|
||||
return TypeCheckResult{}
|
||||
}
|
||||
if arg.expr.is(Token) {
|
||||
tag := typename(s, arg.expr, arg.expr.as(Token))
|
||||
if tag.isValid() {
|
||||
if tag.kind == TagKind.number && tag.q > 0 {
|
||||
return TypeCheckResult { tag: tag }
|
||||
} else {
|
||||
expectedFixedNumberType(s, arg.expr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tr := expression(s, arg.expr)
|
||||
if tr.tag.isValid() {
|
||||
expectedFixedNumberType(s, arg.expr)
|
||||
}
|
||||
}
|
||||
return TypeCheckResult{}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,19 @@ TypeChecker {
|
|||
return "[unknown]"
|
||||
}
|
||||
|
||||
canAssign(s TypeCheckerState, from Tag, fromValue Value, to Tag) {
|
||||
canAssign_andUpgrade(s TypeCheckerState, from Tag, fromValue Value, node Node, to Tag) {
|
||||
if to.kind != TagKind.unknown {
|
||||
if from.kind == TagKind.number {
|
||||
return to.kind == TagKind.number && (to.q == from.q || (from.q == 0 && canConvertFreeConst(s, fromValue, to.q)))
|
||||
if to.kind == TagKind.number {
|
||||
assert(to.q > 0)
|
||||
if to.q == from.q {
|
||||
return true
|
||||
}
|
||||
if from.q == 0 {
|
||||
return canConvertFreeConst_andUpgrade(s, fromValue, node, to)
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else if from.kind == TagKind.moduleOut || from.kind == TagKind.struct_ {
|
||||
return to.kind == from.kind && to.q == from.q
|
||||
}
|
||||
|
|
@ -51,9 +60,10 @@ TypeChecker {
|
|||
return result
|
||||
}
|
||||
|
||||
canConvertFreeConst(s TypeCheckerState, val Value, width int) {
|
||||
if val.kind == ValueKind.ulong_ {
|
||||
return highestBit(val.z) <= width //|| highestBit(~val.z) < width
|
||||
canConvertFreeConst_andUpgrade(s TypeCheckerState, fromValue Value, node Node, to Tag) {
|
||||
if fromValue.kind == ValueKind.ulong_ && highestBit(fromValue.z) <= to.q {
|
||||
s.typeMap.update(node, to)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -163,7 +173,7 @@ TypeChecker {
|
|||
s.errors.add(Error.at(s.unit, op.span, format("Cannot apply operator {} to argument of type {} and target of type {}", op.value, tagString(s.comp, arg), tagString(s.comp, target))))
|
||||
}
|
||||
|
||||
expectedFixedNumber(s TypeCheckerState, e Node) {
|
||||
expectedFixedNumberType(s TypeCheckerState, e Node) {
|
||||
s.errors.add(Error.at(s.unit, RangeFinder.find(e), "Expected: fixed width numeric type"))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ VerilogGenerator {
|
|||
s.globals.add("output")
|
||||
s.globals.add("inout")
|
||||
s.globals.add("case")
|
||||
s.globals.add("signed")
|
||||
|
||||
for u in s.comp.units {
|
||||
for node in u.contents {
|
||||
|
|
@ -785,19 +786,22 @@ VerilogGenerator {
|
|||
value(s GeneratorState, tag Tag, value Value) {
|
||||
s.isNonIndexable = true
|
||||
assert(tag.kind == TagKind.number)
|
||||
if value.kind == ValueKind.ulong_ {
|
||||
if tag.q > 0 {
|
||||
write(s, format("{}'d{}", tag.q, value.z))
|
||||
} else {
|
||||
write(s, format("{}", value.z))
|
||||
if tag.q == 0 {
|
||||
write(s, "(((compiler_bug:invalid_num")
|
||||
}
|
||||
if value.kind == ValueKind.ulong_ {
|
||||
write(s, format("{}'d{}", tag.q, value.z))
|
||||
} else if value.kind == ValueKind.byteArray {
|
||||
data := EmulatorRunner.unpackArray(value)
|
||||
write(s, format("{}'h", tag.q))
|
||||
from := min((tag.q + 7) / 8, data.count)
|
||||
if from > 0 {
|
||||
for i := from - 1; i >= 0; i -= 1 {
|
||||
Util.writeByteHexTo(data[i], s.out.sb)
|
||||
}
|
||||
} else {
|
||||
write(s, "0")
|
||||
}
|
||||
} else {
|
||||
abandon()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue