Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make error messages render Nim code, not NIF code #527

Merged
merged 4 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/hexer/duplifier.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ It follows that we're only interested in Call expressions here, or similar
import std / [assertions]
include nifprelude
import nifindexes, symparser, treemangler, lifter, mover
import ".." / nimony / [nimony_model, programs, decls, typenav]
import ".." / nimony / [nimony_model, programs, decls, typenav, renderer]

type
Context = object
Expand Down Expand Up @@ -604,7 +604,7 @@ proc trEnsureMove(c: var Context; n: var Cursor; e: Expects) =
copyInto c.dest, n:
tr c, n, e
else:
let m = "not the last usage of: " & toString(n, false)
let m = "not the last usage of: " & asNimCode(n)
c.dest.buildTree ErrT, info:
c.dest.add strToken(pool.strings.getOrIncl(m), info)
skip n
Expand Down
56 changes: 56 additions & 0 deletions src/lib/filelinecache.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Nif library
# (c) Copyright 2024 Andreas Rumpf
#
# See the file "license.txt", included in this
# distribution, for details about the copyright.

## Logic for mapping a (file, line, col) key to the file's content.

import std / syncio
import std/[tables, strutils]

type
CachedFile* = object
content: string
lineStarts: seq[int]

FilePosition* = object
line*: int
col*: int

FileLineCache = object
files: Table[string, CachedFile]

var
gFileLineCache: FileLineCache

proc loadFile*(filename: string) =
var entry = CachedFile(content: readFile(filename), lineStarts: @[0])
var nl = find(entry.content, '\n')
while nl > 0:
entry.lineStarts.add nl
nl = find(entry.content, '\n', nl + 1)
gFileLineCache.files[filename] = ensureMove entry

proc extract*(filename: string; start, finish: FilePosition): string =
if not gFileLineCache.files.hasKey(filename):
loadFile(filename)
let entry {.cursor.} = gFileLineCache.files[filename]
let startIdx = entry.lineStarts[start.line-1] + start.col-1
let finishIdx = entry.lineStarts[finish.line-1] + finish.col-1
result = entry.content[startIdx..finishIdx]

proc extract*(filename: string; start: FilePosition): string =
if not gFileLineCache.files.hasKey(filename):
loadFile(filename)
let entry {.cursor.} = gFileLineCache.files[filename]
let startIdx = entry.lineStarts[start.line-1] + start.col-1
if start.line < entry.lineStarts.len:
let finishIdx = entry.lineStarts[start.line]-1
result = entry.content[startIdx..finishIdx]
else:
result = entry.content.substr(startIdx)

when isMainModule:
echo extract("src/lib/filelinecache.nim", FilePosition(line: 1, col: 9), FilePosition(line: 3, col: 2))
echo extract("src/lib/filelinecache.nim", FilePosition(line: 1, col: 9))
2 changes: 2 additions & 0 deletions src/nifc/nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
# instead of the directory of this nim.cfg file.
--outdir: "bin"
--styleCheck: off
# Make NIFC more robust against broken NIF inputs:
--define: showBroken
10 changes: 5 additions & 5 deletions src/nimony/derefs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import std / [assertions]

include nifprelude

import nimony_model, programs, decls, typenav, sembasics, reporters
import nimony_model, programs, decls, typenav, sembasics, reporters, renderer

type
Expects = enum
Expand Down Expand Up @@ -218,7 +218,7 @@ proc trReturn(c: var Context; n: var Cursor) =
else:
let err = c.r.returnType == WantVarTResult and not validBorrowsFrom(c, n)
if err:
buildLocalErr(c.dest, n.info, "cannot borrow from " & toString(n, false))
buildLocalErr(c.dest, n.info, "cannot borrow from " & asNimCode(n))
else:
tr c, n, c.r.returnType
takeParRi c, n
Expand All @@ -228,7 +228,7 @@ proc mightBeDangerous(c: var Context; n: Cursor) =
if root != NoSymId:
for d in items(c.r.dangerousLocations):
if d[0] == root:
buildLocalErr c.dest, n.info, "cannot mutate " & toString(n, false) &
buildLocalErr c.dest, n.info, "cannot mutate " & asNimCode(n) &
"; binding created here: " & infoToStr(d[1].info)

proc checkForDangerousLocations(c: var Context; n: var Cursor) =
Expand Down Expand Up @@ -414,10 +414,10 @@ proc trAsgn(c: var Context; n: var Cursor) =
tr c, n, e
case err
of InvalidBorrow:
buildLocalErr c.dest, n.info, "cannot borrow from " & toString(n, false)
buildLocalErr c.dest, n.info, "cannot borrow from " & asNimCode(n)
skip n
of LocationIsConst:
buildLocalErr c.dest, n.info, "cannot mutate expression " & toString(n, false)
buildLocalErr c.dest, n.info, "cannot mutate expression " & asNimCode(n)
tr c, n, e
tr c, n, e
else:
Expand Down
20 changes: 10 additions & 10 deletions src/nimony/expreval.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import std / assertions

include nifprelude
import nimony_model, decls, programs, xints, semdata
import nimony_model, decls, programs, xints, semdata, renderer

type
EvalContext* = object
Expand Down Expand Up @@ -111,11 +111,11 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor =
skipToEnd n
return a
elif a.exprKind != TrueX:
error "expected bool for operand of `and` but got: " & toString(a, false), n.info
error "expected bool for operand of `and` but got: " & asNimCode(a), n.info
return
let b = propagateError eval(c, n)
if not isConstBoolValue(b):
error "expected bool for operand of `and` but got: " & toString(b, false), n.info
error "expected bool for operand of `and` but got: " & asNimCode(b), n.info
return
else:
skipParRi n
Expand All @@ -127,11 +127,11 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor =
skipToEnd n
return a
elif a.exprKind != FalseX:
error "expected bool for operand of `or` but got: " & toString(a, false), n.info
error "expected bool for operand of `or` but got: " & asNimCode(a), n.info
return
let b = propagateError eval(c, n)
if not isConstBoolValue(b):
error "expected bool for operand of `or` but got: " & toString(b, false), n.info
error "expected bool for operand of `or` but got: " & asNimCode(b), n.info
return
else:
skipParRi n
Expand All @@ -146,7 +146,7 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor =
skipParRi n
return c.getTrueValue()
else:
error "expected bool for operand of `not` but got: " & toString(a, false), n.info
error "expected bool for operand of `not` but got: " & asNimCode(a), n.info
return
of SufX:
# we only need raw value
Expand All @@ -157,7 +157,7 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor =
inc n
skipParRi n
if c.c == nil:
error "cannot evaluate expression at compile time: " & toString(n, false), n.info
error "cannot evaluate expression at compile time: " & asNimCode(n), n.info
elif IsMain in c.c.moduleFlags:
result = c.getTrueValue()
else:
Expand All @@ -167,9 +167,9 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor =
result = n
skip n
else:
error "cannot evaluate expression at compile time: " & toString(n, false), n.info
error "cannot evaluate expression at compile time: " & asNimCode(n), n.info
else:
error "cannot evaluate expression at compile time: " & toString(n, false), n.info
error "cannot evaluate expression at compile time: " & asNimCode(n), n.info

proc evalExpr*(c: var SemContext, n: var Cursor): TokenBuf =
var ec = initEvalContext(addr c)
Expand Down Expand Up @@ -271,7 +271,7 @@ proc bitsetSizeInBytes*(baseType: Cursor): xint =
var index = baseType
inc index # tag
skip index # basetype
# XXX offset not implemented
# XXX offset not implemented
skip index # lo
let hi = evalOrdinal(nil, index)
var err = false
Expand Down
53 changes: 53 additions & 0 deletions src/nimony/renderer.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Nimony
# (c) Copyright 2024 Andreas Rumpf
#
# See the file "license.txt", included in this
# distribution, for details about the copyright.

import ".." / lib / [bitabs, lineinfos, nifstreams, nifcursors, filelinecache]

## Rendering of Nim code from a cursor.

proc asNimCode*(n: Cursor): string =
var m0: PackedLineInfo = NoLineInfo
var m1: PackedLineInfo = NoLineInfo
var nested = 0
var n2 = n
var file0 = FileId 0
while true:
if n2.info.isValid:
let currentFile = getFileId(pool.man, n2.info)
if not m0.isValid:
m0 = n2.info
file0 = currentFile
elif not m1.isValid and currentFile == file0:
m1 = n2.info
case n2.kind
of ParLe:
inc nested
of ParRi:
dec nested
else:
discard
if nested == 0: break
inc n2

when false: #if m0.isValid:
let (_, line0, col0) = unpack(pool.man, m0)
if m1.isValid:
let (_, line1, col1) = unpack(pool.man, m1)
result = extract(pool.files[file0],
FilePosition(line: line0, col: col0),
FilePosition(line: line1, col: col1))
else:
result = extract(pool.files[file0], FilePosition(line: line0, col: col0))
var visible = false
for i in 0..<result.len:
if result[i] > ' ':
visible = true
break
if not visible:
result = toString(n, false)
else:
# Fallback to the NIF representation as it is much better than nothing:
result = toString(n, false)
16 changes: 8 additions & 8 deletions src/nimony/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ include nifprelude
import nimony_model, symtabs, builtintypes, decls, symparser, asthelpers,
programs, sigmatch, magics, reporters, nifconfig, nifindexes,
intervals, xints, typeprops,
semdata, sembasics, semos, expreval, semborrow, enumtostr, derefs, sizeof
semdata, sembasics, semos, expreval, semborrow, enumtostr, derefs, sizeof, renderer

import ".." / gear2 / modnames
import ".." / models / tags
Expand Down Expand Up @@ -636,7 +636,7 @@ proc semConstBoolExpr(c: var SemContext; n: var Cursor) =
if value.kind == ParLe and value.tagId == ErrT:
c.dest.add valueBuf
else:
buildErr c, it.n.info, "expected constant bool value but got: " & toString(value, false)
buildErr c, it.n.info, "expected constant bool value but got: " & asNimCode(value)
else:
c.dest.shrink start
c.dest.add valueBuf
Expand All @@ -656,7 +656,7 @@ proc semConstStrExpr(c: var SemContext; n: var Cursor) =
if value.kind == ParLe and value.tagId == ErrT:
c.dest.add valueBuf
else:
buildErr c, it.n.info, "expected constant string value but got: " & toString(value, false)
buildErr c, it.n.info, "expected constant string value but got: " & asNimCode(value)
else:
c.dest.shrink start
c.dest.add valueBuf
Expand All @@ -676,7 +676,7 @@ proc semConstIntExpr(c: var SemContext; n: var Cursor) =
if value.kind == ParLe and value.tagId == ErrT:
c.dest.add valueBuf
else:
buildErr c, it.n.info, "expected constant integer value but got: " & toString(value, false)
buildErr c, it.n.info, "expected constant integer value but got: " & asNimCode(value)
else:
c.dest.shrink start
c.dest.add valueBuf
Expand Down Expand Up @@ -4442,7 +4442,7 @@ proc semDefined(c: var SemContext; it: var Item) =
let name = getDottedIdent(it.n)
skipParRi it.n
if name == "":
c.buildErr info, "invalid expression for defined: " & toString(orig, false), orig
c.buildErr info, "invalid expression for defined: " & asNimCode(orig), orig
else:
let isDefined = name in c.g.config.defines
let beforeExpr = c.dest.len
Expand Down Expand Up @@ -4474,7 +4474,7 @@ proc semDeclared(c: var SemContext; it: var Item) =
skipToEnd it.n
skipParRi it.n
if nameId == StrId(0):
c.buildErr info, "invalid expression for declared: " & toString(orig, false), orig
c.buildErr info, "invalid expression for declared: " & asNimCode(orig), orig
else:
let isDeclared = isDeclared(c, nameId)
let beforeExpr = c.dest.len
Expand Down Expand Up @@ -5015,7 +5015,7 @@ proc semAddr(c: var SemContext; it: var Item) =
if isAddressable(a):
endRead c.dest
else:
let asStr = toString(a, false)
let asStr = asNimCode(a)
endRead c.dest
c.dest.shrink beforeArg
c.buildErr info, "invalid expression for `addr` operation: " & asStr
Expand Down Expand Up @@ -5063,7 +5063,7 @@ proc semPragmaLine(c: var SemContext; it: var Item; info: PackedLineInfo) =
var args = newSeq[string]()
while it.n.kind != ParRi:
if it.n.kind != StringLit:
buildErr c, it.n.info, "expected `string` but got: " & toString(it.n)
buildErr c, it.n.info, "expected `string` but got: " & asNimCode(it.n)

args.add pool.strings[it.n.litId]
inc it.n
Expand Down
4 changes: 2 additions & 2 deletions src/nimony/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import std / [sets, tables, assertions]

import bitabs, nifreader, nifstreams, nifcursors, lineinfos

import nimony_model, decls, programs, semdata, typeprops, xints, builtintypes
import nimony_model, decls, programs, semdata, typeprops, xints, builtintypes, renderer

type
Item* = object
Expand Down Expand Up @@ -70,7 +70,7 @@ proc concat(a: varargs[string]): string =
for i in 1..high(a): result.add a[i]

proc typeToString*(n: Cursor): string =
result = toString(n, false)
result = asNimCode(n)

proc error(m: var Match; k: MatchErrorKind; expected, got: Cursor) =
if m.err: return # first error is the important one
Expand Down
Loading