Skip to content

Commit d1d8ddb

Browse files
committed
fizzbuzz
2 parents 0fd55d8 + 7f5e015 commit d1d8ddb

File tree

3 files changed

+93
-157
lines changed

3 files changed

+93
-157
lines changed

compiler/semobjconstr.nim

Lines changed: 92 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,16 @@ proc caseBranchMatchesExpr(branch, matched: PNode): bool =
140140
elif exprStructuralEquivalent(branch[i], matched):
141141
return true
142142

143-
proc pickCaseBranches(caseExpr, matched: PNode): seq[PNode] =
143+
proc pickCaseBranches(caseExpr, matched: PNode): seq[int] =
144144
let endsWithElse = caseExpr[^1].kind == nkElse
145145
for i in 1 ..< caseExpr.len - int(endsWithElse):
146146
if caseExpr[i].caseBranchMatchesExpr(matched):
147-
result.add caseExpr[i]
147+
result.add i
148148
if endsWithElse and result.len == 0:
149-
result.add caseExpr[^1]
149+
result.add caseExpr.len - 1
150150

151-
proc pickCaseBranch(caseExpr, matched: PNode): PNode =
152-
# XXX: Perhaps this proc already exists somewhere
153-
let endsWithElse = caseExpr[^1].kind == nkElse
154-
for i in 1 ..< caseExpr.len - int(endsWithElse):
155-
if caseExpr[i].caseBranchMatchesExpr(matched):
156-
return caseExpr[i]
157-
if endsWithElse:
158-
return caseExpr[^1]
151+
proc pickCaseBranch(caseExpr, matched: PNode): int =
152+
pickCaseBranches(caseExpr, matched)[0]
159153

160154
iterator directFieldsInRecList(recList: PNode): PNode =
161155
# XXX: We can remove this case by making all nkOfBranch nodes
@@ -214,80 +208,77 @@ proc semConstructFields(c: PContext, recNode: PNode,
214208

215209
let discriminator = recNode[0]
216210
internalAssert c.config, discriminator.kind == nkSym
217-
var selectedBranch = -1
218-
219-
for i in 1 ..< recNode.len:
220-
let innerRecords = recNode[i][^1]
221-
let status = semConstructFields(c, innerRecords, initExpr, flags)
222-
if status notin {initNone, initUnknown}:
223-
mergeInitStatus(result, status)
224-
if selectedBranch != -1:
225-
let prevFields = fieldsPresentInBranch(selectedBranch)
226-
let currentFields = fieldsPresentInBranch(i)
227-
localError(c.config, initExpr.info,
228-
("The fields '$1' and '$2' cannot be initialized together, " &
229-
"because they are from conflicting branches in the case object.") %
230-
[prevFields, currentFields])
231-
result = initConflict
232-
else:
233-
selectedBranch = i
234-
235-
if selectedBranch != -1:
236-
template badDiscriminatorError =
237-
let fields = fieldsPresentInBranch(selectedBranch)
238-
localError(c.config, initExpr.info,
239-
("cannot prove that it's safe to initialize $1 with " &
240-
"the runtime value for the discriminator '$2' ") %
241-
[fields, discriminator.sym.name.s])
242-
mergeInitStatus(result, initNone)
243-
244-
template wrongBranchError(i) =
245-
let fields = fieldsPresentInBranch(i)
246-
localError(c.config, initExpr.info,
247-
"a case selecting discriminator '$1' with value '$2' " &
248-
"appears in the object construction, but the field(s) $3 " &
249-
"are in conflict with this value.",
250-
[discriminator.sym.name.s, discriminatorVal.renderTree, fields])
251-
252-
template valuesInConflictError(valsDiff) =
253-
localError(c.config, discriminatorVal.info, ("possible values " &
254-
"$2are in conflict with discriminator values for " &
255-
"selected object branch $1.") % [$selectedBranch,
256-
formatUnsafeBranchVals(recNode[0].typ, valsDiff)])
257-
258-
let branchNode = recNode[selectedBranch]
259-
let flags = flags*{efAllowDestructor} + {efPreferStatic,
260-
efPreferNilResult}
261-
var discriminatorVal = semConstrField(c, flags,
262-
discriminator.sym, initExpr)
263-
if discriminatorVal == nil: #Try to use default value
264-
discriminatorVal = discriminator.sym.ast
265-
266-
if discriminatorVal != nil:
267-
discriminatorVal = discriminatorVal.skipHidden
268-
if discriminatorVal.kind notin nkLiterals and (
269-
not isOrdinalType(discriminatorVal.typ, true) or
270-
lengthOrd(c.config, discriminatorVal.typ) > MaxSetElements or
271-
lengthOrd(c.config, recNode[0].typ) > MaxSetElements):
272-
localError(c.config, discriminatorVal.info,
273-
"branch initialization with a runtime discriminator only " &
274-
"supports ordinal types with 2^16 elements or less.")
275211

276-
if discriminatorVal == nil:
277-
badDiscriminatorError()
212+
# for i in 1 ..< recNode.len:
213+
# let innerRecords = recNode[i][^1]
214+
# let status = semConstructFields(c, innerRecords, initExpr, flags)
215+
# if status notin {initNone, initUnknown}:
216+
# mergeInitStatus(result, status)
217+
# if selectedBranch != -1:
218+
# let prevFields = fieldsPresentInBranch(selectedBranch)
219+
# let currentFields = fieldsPresentInBranch(i)
220+
# localError(c.config, initExpr.info,
221+
# ("The fields '$1' and '$2' cannot be initialized together, " &
222+
# "because they are from conflicting branches in the case object.") %
223+
# [prevFields, currentFields])
224+
# result = initConflict
225+
# else:
226+
# selectedBranch = i
227+
228+
229+
# template wrongBranchError(i) =
230+
# let fields = fieldsPresentInBranch(i)
231+
# localError(c.config, initExpr.info,
232+
# "a case selecting discriminator '$1' with value '$2' " &
233+
# "appears in the object construction, but the field(s) $3 " &
234+
# "are in conflict with this value.",
235+
# [discriminator.sym.name.s, discriminatorVal.renderTree, fields])
236+
# let flags = flags*{efAllowDestructor} + {efPreferStatic, efPreferNilResult}
237+
# var discriminatorVal = semConstrField(c, flags, discriminator.sym, initExpr)
238+
template valuesInConflictError(valsDiff) =
239+
localError(c.config, discriminatorVal.info, ("possible values " &
240+
"$2are in conflict with discriminator values for " &
241+
"selected object branch $1.") % [$selectedBranch,
242+
formatUnsafeBranchVals(recNode[0].typ, valsDiff)])
243+
244+
245+
var selectedBranch: int
246+
let defaultValue = discriminator.sym.ast
247+
248+
var discriminatorVal = semConstrField(c, flags + {efPreferStatic}, discriminator.sym, initExpr)
249+
250+
if discriminatorVal == nil and defaultValue == nil:
251+
# None of the branches were explicitly selected by the user and no value
252+
# was given to the discrimator. We can assume that it will be initialized
253+
# to zero and this will select a particular branch as a result:
254+
selectedBranch = recNode.pickCaseBranch newIntLit(c.graph, initExpr.info, 0)
255+
checkMissingFields recNode[selectedBranch], true
256+
elif defaultValue != nil:
257+
# Try to use default value
258+
discriminatorVal = defaultValue
259+
selectedBranch = recNode.pickCaseBranch defaultValue
260+
checkMissingFields recNode[selectedBranch], true
261+
else:
262+
discriminatorVal = discriminatorVal.skipHidden
263+
if discriminatorVal.kind == nkIntLit:
264+
# Discriminator is a compile-time value, we know which branch will be selected
265+
selectedBranch = recNode.pickCaseBranch discriminatorVal
266+
if selectedBranch != 0: checkMissingFields recNode[selectedBranch], true
267+
elif discriminatorVal.typ.kind == tyRange:
268+
let selectedBranches = recNode.pickCaseBranches discriminatorVal.typ.n
269+
for b in selectedBranches:
270+
checkMissingFields recNode[b], selectedBranches.len == 0
278271
elif discriminatorVal.kind == nkSym:
279272
let (ctorCase, ctorIdx) = findUsefulCaseContext(c, discriminatorVal)
280273
if ctorCase == nil:
281-
if discriminatorVal.typ.kind == tyRange:
282-
let rangeVals = rangeTypVals(discriminatorVal.typ)
283-
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
284-
let diff = rangeVals - recBranchVals
285-
if diff.len != 0:
286-
valuesInConflictError(diff)
287-
else:
288-
badDiscriminatorError()
274+
let fields = fieldsPresentInBranch(selectedBranch)
275+
localError(c.config, initExpr.info,
276+
("cannot prove that it's safe to initialize $1 with " &
277+
"the runtime value for the discriminator '$2' ") %
278+
[fields, discriminator.sym.name.s])
279+
mergeInitStatus(result, initNone)
289280
elif discriminatorVal.sym.kind notin {skLet, skParam} or
290-
discriminatorVal.sym.typ.kind == tyVar:
281+
discriminatorVal.sym.typ.kind == tyVar:
291282
localError(c.config, discriminatorVal.info,
292283
"runtime discriminator must be immutable if branch fields are " &
293284
"initialized, a 'let' binding is required.")
@@ -303,65 +294,11 @@ proc semConstructFields(c: PContext, recNode: PNode,
303294
if branchValsDiff.len != 0:
304295
valuesInConflictError(branchValsDiff)
305296
else:
306-
var failedBranch = -1
307-
if branchNode.kind != nkElse:
308-
if not branchNode.caseBranchMatchesExpr(discriminatorVal):
309-
failedBranch = selectedBranch
310-
else:
311-
# With an else clause, check that all other branches don't match:
312-
for i in 1 .. (recNode.len - 2):
313-
if recNode[i].caseBranchMatchesExpr(discriminatorVal):
314-
failedBranch = i
315-
break
316-
if failedBranch != -1:
317-
if discriminatorVal.typ.kind == tyRange:
318-
let rangeVals = rangeTypVals(discriminatorVal.typ)
319-
let recBranchVals = branchVals(c, recNode, selectedBranch, false)
320-
let diff = rangeVals - recBranchVals
321-
if diff.len != 0:
322-
valuesInConflictError(diff)
323-
else:
324-
wrongBranchError(failedBranch)
325-
326-
# When a branch is selected with a partial match, some of the fields
327-
# that were not initialized may be mandatory. We must check for this:
328-
if result == initPartial:
329-
checkMissingFields branchNode, true
330-
331-
else:
332-
result = initNone
333-
var discriminatorVal = semConstrField(c, flags + {efPreferStatic}, discriminator.sym, initExpr)
334-
335-
var matchedBranch: PNode
336-
337-
if discriminatorVal == nil: #Try to use default value
338-
discriminatorVal = discriminator.sym.ast
339-
340-
if discriminatorVal == nil:
341-
# None of the branches were explicitly selected by the user and no
342-
# value was given to the discrimator. We can assume that it will be
343-
# initialized to zero and this will select a particular branch as
344-
# a result:
345-
matchedBranch = recNode.pickCaseBranch newIntLit(c.graph, initExpr.info, 0)
346-
checkMissingFields matchedBranch, true
347-
else:
348-
result = initPartial
349-
discriminatorVal = discriminatorVal.skipHidden
350-
debug discriminatorVal
351-
if discriminatorVal.kind == nkIntLit: #or discriminatorVal.typ.kind == tyRange:
352-
# When the discriminator is a compile-time value, we also know
353-
# which branch will be selected:
354-
matchedBranch = recNode.pickCaseBranch discriminatorVal
355-
if matchedBranch != nil: checkMissingFields matchedBranch, true
356-
elif discriminatorVal.typ.kind == tyRange:
357-
let matchedBranches = recNode.pickCaseBranches discriminatorVal.typ.n
358-
for m in matchedBranches:
359-
checkMissingFields m, matchedBranches.len == 0
360-
else:
361-
# All bets are off. If any of the branches has a mandatory
362-
# fields we must produce an error:
363-
for i in 1 ..< recNode.len: checkMissingFields recNode[i], false
297+
# All bets are off. If any of the branches has a mandatory
298+
# fields we must produce an error:
299+
for i in 1 ..< recNode.len: checkMissingFields recNode[i], false
364300

301+
discard semConstructFields(c, recNode[selectedBranch][^1], initExpr, flags)
365302
of nkSym:
366303
let field = recNode.sym
367304
let e = semConstrField(c, flags, field, initExpr)
@@ -428,20 +365,20 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
428365
# Since we were traversing the object fields, it's possible that
429366
# not all of the fields specified in the constructor was visited.
430367
# We'll check for such fields here:
431-
for i in 1..<reslen:
432-
let field = result[i]
433-
if nfSem notin field.flags:
434-
if field.kind != nkExprColonExpr:
435-
invalidObjConstr(c, field)
436-
continue
437-
let id = considerQuotedIdent(c, field[0])
438-
# This node was not processed. There are two possible reasons:
439-
# 1) It was shadowed by a field with the same name on the left
440-
for j in 1 ..< i:
441-
let prevId = considerQuotedIdent(c, result[j][0])
442-
if prevId.id == id.id:
443-
localError(c.config, field.info, errFieldInitTwice % id.s)
444-
return
445-
# 2) No such field exists in the constructed type
446-
localError(c.config, field.info, errUndeclaredFieldX % id.s)
447-
return
368+
# for i in 1..<reslen:
369+
# let field = result[i]
370+
# if nfSem notin field.flags:
371+
# if field.kind != nkExprColonExpr:
372+
# invalidObjConstr(c, field)
373+
# continue
374+
# let id = considerQuotedIdent(c, field[0])
375+
# # This node was not processed. There are two possible reasons:
376+
# # 1) It was shadowed by a field with the same name on the left
377+
# for j in 1 ..< i:
378+
# let prevId = considerQuotedIdent(c, result[j][0])
379+
# if prevId.id == id.id:
380+
# localError(c.config, field.info, errFieldInitTwice % id.s)
381+
# return
382+
# # 2) No such field exists in the constructed type
383+
# localError(c.config, field.info, errUndeclaredFieldX % id.s)
384+
# return

compiler/semtypes.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
745745
if n[^1].kind != nkEmpty:
746746
n[^1] = semConstExpr(c, n[^1])
747747
fSym.sym.ast = n[^1]
748-
elif typ.kind in {tyRange, tyOrdinal}:
748+
elif typ.kind in {tyRange, tyOrdinal}: #Node flag? Handle embedded objects?
749749
fSym.sym.ast = newIntNode(nkIntLit, firstOrd(c.config, typ))
750750
if a.kind == nkEmpty: addSon(father, newSymNode(f))
751751
else: addSon(a, newSymNode(f))

compiler/transf.nim

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,6 @@ proc containsResult(n: PNode): bool =
969969
# echo recNode.kind; debug recNode; internalAssert c.config, false
970970

971971

972-
973972
proc transform(c: PTransf, n: PNode): PNode =
974973
when false:
975974
var oldDeferAnchor: PNode

0 commit comments

Comments
 (0)