mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
fixed merge conflict
This commit is contained in:
34
.github/workflows/bisects.yml
vendored
34
.github/workflows/bisects.yml
vendored
@@ -5,19 +5,27 @@ on:
|
||||
types: created
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
bisects:
|
||||
if: |
|
||||
github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '!nim ') && github.event.issue.pull_request == null && github.event.comment.author_association != 'NONE'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest, windows-latest, macos-latest]
|
||||
name: ${{ matrix.platform }}-bisects
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# nimrun-action requires Nim installed.
|
||||
- uses: jiro4989/setup-nim-action@v1
|
||||
with:
|
||||
nim-version: 'devel'
|
||||
- uses: jiro4989/setup-nim-action@v1
|
||||
with:
|
||||
nim-version: 'devel'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install --no-install-recommends -yq valgrind
|
||||
|
||||
- uses: juancarlospaco/nimrun-action@nim
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: juancarlospaco/nimrun-action@nim
|
||||
if: |
|
||||
runner.os == 'Linux' && contains(github.event.comment.body, '-d:linux' ) ||
|
||||
runner.os == 'Windows' && contains(github.event.comment.body, '-d:windows') ||
|
||||
runner.os == 'macOS' && contains(github.event.comment.body, '-d:osx' ) ||
|
||||
runner.os == 'Linux' && !contains(github.event.comment.body, '-d:linux') && !contains(github.event.comment.body, '-d:windows') && !contains(github.event.comment.body, '-d:osx')
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
6
.github/workflows/ci_bench.yml
vendored
6
.github/workflows/ci_bench.yml
vendored
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
6
.github/workflows/ci_packages.yml
vendored
6
.github/workflows/ci_packages.yml
vendored
@@ -32,10 +32,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
6
.github/workflows/ci_publish.yml
vendored
6
.github/workflows/ci_publish.yml
vendored
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
@@ -73,8 +73,8 @@ jobs:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install node.js 16.x'
|
||||
versionSpec: '20.x'
|
||||
displayName: 'Install node.js 20.x'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'))
|
||||
|
||||
- bash: |
|
||||
|
||||
17
changelog.md
17
changelog.md
@@ -3,29 +3,44 @@
|
||||
|
||||
## Changes affecting backward compatibility
|
||||
|
||||
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
|
||||
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
|
||||
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
|
||||
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
|
||||
- Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one.
|
||||
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
|
||||
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
|
||||
|
||||
[//]: # "Additions:"
|
||||
|
||||
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
|
||||
- Added `setLenUninit` to system, which doesn't initalize
|
||||
slots when enlarging a sequence.
|
||||
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
|
||||
- Added Viewport API for the JavaScript targets in the `dom` module.
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
|
||||
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
|
||||
|
||||
[//]: # "Removals:"
|
||||
|
||||
|
||||
## Language changes
|
||||
|
||||
|
||||
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
|
||||
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer
|
||||
- `member` can be used to attach a procedure to a C++ type.
|
||||
- C++ `constructor` now reuses `result` instead creating `this`.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
|
||||
|
||||
## Tool changes
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
proc prc(): int =
|
||||
123
|
||||
|
||||
iterator iter(): int =
|
||||
iterator iter(): int {.closure.} =
|
||||
yield 123
|
||||
|
||||
proc takesProc[T: proc](x: T) = discard
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
## Simple alias analysis for the HLO and the code generators.
|
||||
|
||||
import
|
||||
ast, astalgo, types, trees, intsets
|
||||
ast, astalgo, types, trees
|
||||
|
||||
import std/intsets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
lineinfos, hashes, options, ropes, idents, int128, tables
|
||||
from strutils import toLowerAscii
|
||||
lineinfos, options, ropes, idents, int128, wordrecg
|
||||
|
||||
import std/[tables, hashes]
|
||||
from std/strutils import toLowerAscii
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -901,6 +903,7 @@ type
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
@@ -924,7 +927,7 @@ type
|
||||
# for variables a slot index for the evaluator
|
||||
offset*: int32 # offset of record field
|
||||
disamb*: int32 # disambiguation number; the basic idea is that
|
||||
# `<procname>__<module>_<disamb>`
|
||||
# `<procname>__<module>_<disamb>` is unique
|
||||
loc*: TLoc
|
||||
annex*: PLib # additional fields (seldom used, so we use a
|
||||
# reference to another object to save space)
|
||||
@@ -936,7 +939,7 @@ type
|
||||
# it won't cause problems
|
||||
# for skModule the string literal to output for
|
||||
# deprecated modules.
|
||||
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
|
||||
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
|
||||
when defined(nimsuggest):
|
||||
allUsages*: seq[TLineInfo]
|
||||
|
||||
@@ -1163,7 +1166,7 @@ proc idGeneratorFromModule*(m: PSym): IdGenerator =
|
||||
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
|
||||
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
|
||||
|
||||
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
|
||||
proc nextSymId(x: IdGenerator): ItemId {.inline.} =
|
||||
assert(not x.sealed)
|
||||
inc x.symId
|
||||
result = ItemId(module: x.module, item: x.symId)
|
||||
@@ -1544,7 +1547,8 @@ iterator items*(t: PType): PType =
|
||||
iterator pairs*(n: PType): tuple[i: int, n: PType] =
|
||||
for i in 0..<n.sons.len: yield (i, n.sons[i])
|
||||
|
||||
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
|
||||
proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] = @[]): PType =
|
||||
let id = nextTypeId idgen
|
||||
result = PType(kind: kind, owner: owner, size: defaultSize,
|
||||
align: defaultAlignment, itemId: id,
|
||||
uniqueId: id, sons: sons)
|
||||
@@ -1553,12 +1557,15 @@ proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]):
|
||||
echo "KNID ", kind
|
||||
writeStackTrace()
|
||||
|
||||
template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
|
||||
template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType =
|
||||
newType(kind, id, owner, parent.sons)
|
||||
|
||||
proc newType*(prev: PType, sons: seq[PType]): PType =
|
||||
result = prev
|
||||
result.sons = sons
|
||||
proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons
|
||||
|
||||
when false:
|
||||
proc newType*(prev: PType, sons: seq[PType]): PType =
|
||||
result = prev
|
||||
result.sons = sons
|
||||
|
||||
proc addSon*(father, son: PType) =
|
||||
# todo fixme: in IC, `son` might be nil
|
||||
@@ -1592,13 +1599,17 @@ proc assignType*(dest, src: PType) =
|
||||
newSons(dest, src.len)
|
||||
for i in 0..<src.len: dest[i] = src[i]
|
||||
|
||||
proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
|
||||
result = newType(t.kind, id, owner)
|
||||
proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
|
||||
result = newType(t.kind, idgen, owner)
|
||||
assignType(result, t)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc exactReplica*(t: PType): PType =
|
||||
result = copyType(t, t.itemId, t.owner)
|
||||
result = PType(kind: t.kind, owner: t.owner, size: defaultSize,
|
||||
align: defaultAlignment, itemId: t.itemId,
|
||||
uniqueId: t.uniqueId)
|
||||
assignType(result, t)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
|
||||
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
|
||||
@@ -1989,7 +2000,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType =
|
||||
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||
result = typ
|
||||
if typ.kind != kind:
|
||||
result = newType(kind, nextTypeId(idgen), typ.owner)
|
||||
result = newType(kind, idgen, typ.owner)
|
||||
rawAddSon(result, typ)
|
||||
|
||||
proc toRef*(typ: PType; idgen: IdGenerator): PType =
|
||||
@@ -1997,7 +2008,7 @@ proc toRef*(typ: PType; idgen: IdGenerator): PType =
|
||||
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||
result = typ
|
||||
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
|
||||
result = newType(tyRef, nextTypeId(idgen), typ.owner)
|
||||
result = newType(tyRef, idgen, typ.owner)
|
||||
rawAddSon(result, typ)
|
||||
|
||||
proc toObject*(typ: PType): PType =
|
||||
@@ -2042,7 +2053,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||
result = false
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
|
||||
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
|
||||
|
||||
proc skipColon*(n: PNode): PNode =
|
||||
result = n
|
||||
@@ -2105,8 +2116,8 @@ proc isSinkParam*(s: PSym): bool {.inline.} =
|
||||
proc isSinkType*(t: PType): bool {.inline.} =
|
||||
t.kind == tySink or tfHasOwned in t.flags
|
||||
|
||||
proc newProcType*(info: TLineInfo; id: ItemId; owner: PSym): PType =
|
||||
result = newType(tyProc, id, owner)
|
||||
proc newProcType*(info: TLineInfo; idgen: IdGenerator; owner: PSym): PType =
|
||||
result = newType(tyProc, idgen, owner)
|
||||
result.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result, nil) # return type
|
||||
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
||||
@@ -2157,7 +2168,7 @@ proc toHumanStr*(kind: TTypeKind): string =
|
||||
## strips leading `tk`
|
||||
result = toHumanStrImpl(kind, 2)
|
||||
|
||||
proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n[0] else: n)
|
||||
|
||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||
@@ -2173,3 +2184,7 @@ const
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
|
||||
|
||||
proc isTrue*(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
|
||||
n.kind == nkIntLit and n.intVal != 0
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
# the data structures here are used in various places of the compiler.
|
||||
|
||||
import
|
||||
ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils,
|
||||
ast, options, lineinfos, ropes, idents, rodutils,
|
||||
msgs
|
||||
|
||||
import strutils except addf
|
||||
import std/[hashes, intsets]
|
||||
import std/strutils except addf
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -408,7 +409,7 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1
|
||||
var marker = initIntSet()
|
||||
result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
|
||||
|
||||
import tables
|
||||
import std/tables
|
||||
|
||||
const backrefStyle = "\e[90m"
|
||||
const enumStyle = "\e[34m"
|
||||
|
||||
@@ -90,3 +90,8 @@ proc bitSetCard*(x: TBitSet): BiggestInt =
|
||||
result = 0
|
||||
for it in x:
|
||||
result.inc int(populationCount[it])
|
||||
|
||||
proc bitSetToWord*(s: TBitSet; size: int): BiggestUInt =
|
||||
result = 0
|
||||
for j in 0..<size:
|
||||
if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))
|
||||
|
||||
@@ -221,7 +221,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
|
||||
result.add x & ", " & y
|
||||
else:
|
||||
var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if reifiedOpenArray(n):
|
||||
@@ -277,7 +277,7 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
var a = initLocExpr(p, n[0])
|
||||
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
|
||||
@@ -287,7 +287,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
|
||||
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
|
||||
var n = if n.kind != nkHiddenAddr: n else: n[0]
|
||||
openArrayLoc(p, param.typ, n, result)
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
|
||||
(optByRef notin param.options or not p.module.compileToCpp):
|
||||
a = initLocExpr(p, n)
|
||||
if n.kind in {nkCharLit..nkNilLit}:
|
||||
@@ -417,7 +417,7 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# this is a hotspot in the compiler
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var op = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
|
||||
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
|
||||
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var op = initLocExpr(p, ri[0])
|
||||
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInstOwned)
|
||||
@@ -672,7 +672,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
|
||||
result.add(substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var op = initLocExpr(p, ri[0])
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -716,7 +716,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
# generates a crappy ObjC call
|
||||
var op: TLoc = initLocExpr(p, ri[0])
|
||||
var op = initLocExpr(p, ri[0])
|
||||
var pl = "["
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||
|
||||
@@ -112,11 +112,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Rope) =
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Rope) =
|
||||
genLiteral(p, n, n.typ, result)
|
||||
|
||||
proc bitSetToWord(s: TBitSet, size: int): BiggestUInt =
|
||||
result = 0
|
||||
for j in 0..<size:
|
||||
if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))
|
||||
|
||||
proc genRawSetData(cs: TBitSet, size: int; result: var Rope) =
|
||||
if size > 8:
|
||||
var res = "{\n"
|
||||
@@ -856,6 +851,12 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
|
||||
|
||||
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc = default(TLoc)
|
||||
if p.module.compileToCpp and e.kind == nkDotExpr and e[1].kind == nkSym and e[1].typ.kind == tyPtr:
|
||||
# special case for C++: we need to pull the type of the field as member and friends require the complete type.
|
||||
let typ = e[1].typ[0]
|
||||
if typ.itemId in p.module.g.graph.memberProcsPerType:
|
||||
discard getTypeDesc(p.module, typ)
|
||||
|
||||
genRecordFieldAux(p, e, d, a)
|
||||
var r = rdLoc(a)
|
||||
var f = e[1].sym
|
||||
@@ -1561,7 +1562,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
if e[i].len == 3 and optFieldCheck in p.options:
|
||||
check = e[i][2]
|
||||
genFieldObjConstr(p, ty, useTemp, isRef, e[i][0], e[i][1], check, d, r, e.info)
|
||||
|
||||
|
||||
if useTemp:
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
@@ -1868,8 +1869,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
else:
|
||||
unaryExpr(p, e, d, "$1.Field1")
|
||||
of tyCstring:
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
||||
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
||||
if op == mHigh: unaryExpr(p, e, d, "(#nimCStrLen($1)-1)")
|
||||
else: unaryExpr(p, e, d, "#nimCStrLen($1)")
|
||||
of tyString:
|
||||
var a: TLoc = initLocExpr(p, e[1])
|
||||
var x = lenExpr(p, a)
|
||||
@@ -1889,13 +1890,6 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
|
||||
else: internalError(p.config, e.info, "genArrayLen()")
|
||||
|
||||
proc makeAddr(n: PNode; idgen: IdGenerator): PNode =
|
||||
if n.kind == nkHiddenAddr:
|
||||
result = n
|
||||
else:
|
||||
result = newTree(nkHiddenAddr, n)
|
||||
result.typ = makePtrType(n.typ, idgen)
|
||||
|
||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
e[1] = makeAddr(e[1], p.module.idgen)
|
||||
@@ -2291,9 +2285,6 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
else:
|
||||
binaryArith(p, e, d, m)
|
||||
|
||||
proc skipAddr(n: PNode): PNode =
|
||||
result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n
|
||||
|
||||
proc genWasMoved(p: BProc; n: PNode) =
|
||||
var a: TLoc
|
||||
let n1 = n[1].skipAddr
|
||||
@@ -2521,8 +2512,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mOrd: genOrd(p, e, d)
|
||||
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
|
||||
genArrayLen(p, e, d, op)
|
||||
of mGCref: unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n")
|
||||
of mGCunref: unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n")
|
||||
of mGCref:
|
||||
# only a magic for the old GCs
|
||||
unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n")
|
||||
of mGCunref:
|
||||
# only a magic for the old GCs
|
||||
unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n")
|
||||
of mSetLengthStr: genSetLengthStr(p, e, d)
|
||||
of mSetLengthSeq: genSetLengthSeq(p, e, d)
|
||||
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
|
||||
@@ -3217,22 +3212,6 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) =
|
||||
else:
|
||||
globalError(p.config, info, "cannot create null element for: " & $t.kind)
|
||||
|
||||
proc caseObjDefaultBranch(obj: PNode; branch: Int128): int =
|
||||
result = 0
|
||||
for i in 1 ..< obj.len:
|
||||
for j in 0 .. obj[i].len - 2:
|
||||
if obj[i][j].kind == nkRange:
|
||||
let x = getOrdValue(obj[i][j][0])
|
||||
let y = getOrdValue(obj[i][j][1])
|
||||
if branch >= x and branch <= y:
|
||||
return i
|
||||
elif getOrdValue(obj[i][j]) == branch:
|
||||
return i
|
||||
if obj[i].len == 1:
|
||||
# else branch
|
||||
return i
|
||||
assert(false, "unreachable")
|
||||
|
||||
proc isEmptyCaseObjectBranch(n: PNode): bool =
|
||||
for it in n:
|
||||
if it.kind == nkSym and not isEmptyType(it.sym.typ): return false
|
||||
|
||||
@@ -95,11 +95,11 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
else:
|
||||
raiseAssert "unexpected set type kind"
|
||||
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
|
||||
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
|
||||
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
|
||||
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
|
||||
discard
|
||||
|
||||
proc specializeReset(p: BProc, a: TLoc) =
|
||||
|
||||
@@ -289,14 +289,22 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
|
||||
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
|
||||
genBracedInit(p, value, isConst = false, v.typ, result)
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
|
||||
var params = newRopeAppender()
|
||||
proc genCppParamsForCtor(p: BProc; call: PNode): string =
|
||||
result = ""
|
||||
var argsCounter = 0
|
||||
let typ = skipTypes(value[0].typ, abstractInst)
|
||||
let typ = skipTypes(call[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1..<value.len:
|
||||
for i in 1..<call.len:
|
||||
assert(typ.len == typ.n.len)
|
||||
genOtherArg(p, value, i, typ, params, argsCounter)
|
||||
#if it's a type we can just generate here another initializer as we are in an initializer context
|
||||
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
|
||||
if argsCounter > 0: result.add ","
|
||||
result.add genCppInitializer(p.module, p, call[i][0].sym.typ)
|
||||
else:
|
||||
genOtherArg(p, call, i, typ, result, argsCounter)
|
||||
|
||||
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope) =
|
||||
let params = genCppParamsForCtor(p, call)
|
||||
if params.len == 0:
|
||||
decl = runtimeFormat("$#;\n", [decl])
|
||||
else:
|
||||
@@ -358,7 +366,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
var decl = localVarDecl(p, vn)
|
||||
var tmp: TLoc
|
||||
if isCppCtorCall:
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
genCppVarForCtor(p, value, decl)
|
||||
line(p, cpsStmts, decl)
|
||||
else:
|
||||
tmp = initLocExprSingleUse(p, value)
|
||||
@@ -963,8 +971,11 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
hasDefault = true
|
||||
exprBlock(p, branch.lastSon, d)
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n", [])
|
||||
if not hasDefault:
|
||||
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
|
||||
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
|
||||
elif hasAssume in CC[p.config.cCompiler].props:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n", [])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
if lend != "": fixLabel(p, lend)
|
||||
|
||||
@@ -1446,7 +1457,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
|
||||
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
# ------------------------- Name Mangling --------------------------------
|
||||
|
||||
import sighashes, modulegraphs, strscans
|
||||
import sighashes, modulegraphs, std/strscans
|
||||
import ../dist/checksums/src/checksums/md5
|
||||
import std/sequtils
|
||||
|
||||
type
|
||||
TypeDescKind = enum
|
||||
@@ -24,7 +25,7 @@ type
|
||||
dkResult #skResult
|
||||
dkConst #skConst
|
||||
dkOther #skType, skTemp, skLet and skForVar so far
|
||||
|
||||
|
||||
proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
|
||||
case kind
|
||||
of skParam: dkParam
|
||||
@@ -33,7 +34,7 @@ proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
|
||||
of skResult: dkResult
|
||||
of skConst: dkConst
|
||||
else: dkOther
|
||||
|
||||
|
||||
proc isKeyword(w: PIdent): bool =
|
||||
# Nim and C++ share some keywords
|
||||
# it's more efficient to test the whole Nim keywords range
|
||||
@@ -464,7 +465,7 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
|
||||
var num = 0
|
||||
while i < frmt.len:
|
||||
if frmt[i] == c:
|
||||
inc(i)
|
||||
inc(i)
|
||||
case frmt[i]
|
||||
of c:
|
||||
res.add(c)
|
||||
@@ -521,7 +522,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
|
||||
types.add getTypeDescWeak(m, this.typ, check, dkParam)
|
||||
|
||||
let firstParam = if isCtor: 1 else: 2
|
||||
for i in firstParam..<t.n.len:
|
||||
for i in firstParam..<t.n.len:
|
||||
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genMemberProcParams")
|
||||
var param = t.n[i].sym
|
||||
var descKind = dkParam
|
||||
@@ -649,13 +650,28 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
|
||||
result = rope(mangleField(m, field.name))
|
||||
if result == "": internalError(m.config, field.info, "mangleRecFieldName")
|
||||
|
||||
proc hasCppCtor(m: BModule; typ: PType): bool =
|
||||
proc hasCppCtor(m: BModule; typ: PType): bool =
|
||||
result = false
|
||||
if m.compileToCpp and typ != nil and typ.itemId in m.g.graph.memberProcsPerType:
|
||||
for prc in m.g.graph.memberProcsPerType[typ.itemId]:
|
||||
if sfConstructor in prc.flags:
|
||||
return true
|
||||
|
||||
proc genCppParamsForCtor(p: BProc; call: PNode): string
|
||||
|
||||
proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
|
||||
#To avoid creating a BProc per test when called inside a struct nil BProc is allowed
|
||||
result = "{}"
|
||||
if typ.itemId in m.g.graph.initializersPerType:
|
||||
let call = m.g.graph.initializersPerType[typ.itemId]
|
||||
if call != nil:
|
||||
var p = prc
|
||||
if p == nil:
|
||||
p = BProc(module: m)
|
||||
result = "{" & genCppParamsForCtor(p, call) & "}"
|
||||
if prc == nil:
|
||||
assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
|
||||
|
||||
proc genRecordFieldsAux(m: BModule; n: PNode,
|
||||
rectype: PType,
|
||||
check: var IntSet; result: var Rope; unionPrefix = "") =
|
||||
@@ -720,8 +736,10 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
if fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ):
|
||||
result.addf("\t$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
|
||||
let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
|
||||
if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
|
||||
var initializer = genCppInitializer(m, nil, fieldType)
|
||||
result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
|
||||
else:
|
||||
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
|
||||
else: internalError(m.config, n.info, "genRecordFieldsAux()")
|
||||
@@ -740,12 +758,13 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
|
||||
isCtorGen = true
|
||||
if prc.typ.n.len == 1:
|
||||
isDefaultCtorGen = true
|
||||
if lfNoDecl in prc.loc.flags: continue
|
||||
genMemberProcHeader(m, prc, header, false, true)
|
||||
result.addf "$1;$n", [header]
|
||||
if isCtorGen and not isDefaultCtorGen:
|
||||
var ch: IntSet
|
||||
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
|
||||
|
||||
|
||||
proc fillObjectFields*(m: BModule; typ: PType) =
|
||||
# sometimes generic objects are not consistently merged. We patch over
|
||||
# this fact here.
|
||||
@@ -753,7 +772,7 @@ proc fillObjectFields*(m: BModule; typ: PType) =
|
||||
discard getRecordFields(m, typ, check)
|
||||
|
||||
proc mangleDynLibProc(sym: PSym): Rope
|
||||
|
||||
|
||||
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
|
||||
check: var IntSet, hasField:var bool): Rope =
|
||||
result = ""
|
||||
@@ -798,7 +817,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
|
||||
else:
|
||||
structOrUnion = structOrUnion(typ)
|
||||
var baseType: string = ""
|
||||
if typ[0] != nil:
|
||||
if typ[0] != nil:
|
||||
baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
|
||||
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
|
||||
result = structOrUnion & " " & name
|
||||
@@ -1110,8 +1129,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
result = ""
|
||||
# fixes bug #145:
|
||||
excl(check, t.id)
|
||||
|
||||
|
||||
|
||||
|
||||
proc getTypeDesc(m: BModule; typ: PType; kind = dkParam): Rope =
|
||||
var check = initIntSet()
|
||||
result = getTypeDescAux(m, typ, check, kind)
|
||||
@@ -1196,7 +1215,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
|
||||
var name, params, rettype, superCall: string = ""
|
||||
var isFnConst, isOverride, isMemberVirtual: bool = false
|
||||
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
|
||||
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
|
||||
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
|
||||
let isVirtual = sfVirtual in prc.flags or isMemberVirtual
|
||||
var fnConst, override: string = ""
|
||||
if isCtor:
|
||||
@@ -1206,7 +1225,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
|
||||
if isFwdDecl:
|
||||
if isVirtual:
|
||||
rettype = "virtual " & rettype
|
||||
if isOverride:
|
||||
if isOverride:
|
||||
override = " override"
|
||||
superCall = ""
|
||||
else:
|
||||
@@ -1214,14 +1233,14 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
|
||||
prc.loc.r = "$1$2(@)" % [memberOp, name]
|
||||
elif superCall != "":
|
||||
superCall = " : " & superCall
|
||||
|
||||
|
||||
name = "$1::$2" % [typDesc, name]
|
||||
|
||||
result.add "N_LIB_PRIVATE "
|
||||
result.addf("$1$2($3, $4)$5$6$7$8",
|
||||
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
|
||||
params, fnConst, override, superCall])
|
||||
|
||||
|
||||
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) =
|
||||
# using static is needed for inline procs
|
||||
var check = initIntSet()
|
||||
@@ -1512,9 +1531,9 @@ proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
|
||||
|
||||
proc fakeClosureType(m: BModule; owner: PSym): PType =
|
||||
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
|
||||
result = newType(tyTuple, nextTypeId m.idgen, owner)
|
||||
result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner))
|
||||
var r = newType(tyRef, nextTypeId m.idgen, owner)
|
||||
result = newType(tyTuple, m.idgen, owner)
|
||||
result.rawAddSon(newType(tyPointer, m.idgen, owner))
|
||||
var r = newType(tyRef, m.idgen, owner)
|
||||
let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false)
|
||||
r.rawAddSon(obj)
|
||||
result.rawAddSon(r)
|
||||
@@ -1557,10 +1576,6 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||
|
||||
proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0
|
||||
|
||||
proc makePtrType(baseType: PType; idgen: IdGenerator): PType =
|
||||
result = newType(tyPtr, nextTypeId idgen, baseType.owner)
|
||||
addSonSkipIntLit(result, baseType, idgen)
|
||||
|
||||
proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator; theProc: PSym): PSym =
|
||||
# the wrapper is roughly like:
|
||||
@@ -1572,7 +1587,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
|
||||
|
||||
dest.typ = getSysType(g, info, tyPointer)
|
||||
|
||||
result.typ = newProcType(info, nextTypeId(idgen), owner)
|
||||
result.typ = newProcType(info, idgen, owner)
|
||||
result.typ.addParam dest
|
||||
|
||||
var n = newNodeI(nkProcDef, info, bodyPos+1)
|
||||
@@ -1663,6 +1678,13 @@ proc genDisplay(m: BModule; t: PType, depth: int): Rope =
|
||||
result.add seqs[0]
|
||||
result.add "}"
|
||||
|
||||
proc genVTable(seqs: seq[PSym]): string =
|
||||
result = "{"
|
||||
for i in 0..<seqs.len:
|
||||
if i > 0: result.add ", "
|
||||
result.add "(void *) " & seqs[i].loc.r
|
||||
result.add "}"
|
||||
|
||||
proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
|
||||
cgsym(m, "TNimTypeV2")
|
||||
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
|
||||
@@ -1699,6 +1721,14 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
|
||||
m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay])
|
||||
addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)])
|
||||
|
||||
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
|
||||
if dispatchMethods.len > 0:
|
||||
let vTablePointerName = getTempName(m)
|
||||
m.s[cfsVars].addf("static void* $1[$2] = $3;$n", [vTablePointerName, rope(dispatchMethods.len), genVTable(dispatchMethods)])
|
||||
for i in dispatchMethods:
|
||||
genProcPrototype(m, i)
|
||||
addf(typeEntry, "$1.vTable = $2;$n", [name, vTablePointerName])
|
||||
|
||||
m.s[cfsTypeInit3].add typeEntry
|
||||
|
||||
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
|
||||
@@ -1740,8 +1770,16 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
|
||||
add(typeEntry, ", .traceImpl = (void*)")
|
||||
genHook(m, t, info, attachedTrace, typeEntry)
|
||||
|
||||
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
|
||||
m.s[cfsVars].add typeEntry
|
||||
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
|
||||
if dispatchMethods.len > 0:
|
||||
addf(typeEntry, ", .flags = $1", [rope(flags)])
|
||||
for i in dispatchMethods:
|
||||
genProcPrototype(m, i)
|
||||
addf(typeEntry, ", .vTable = $1};$n", [genVTable(dispatchMethods)])
|
||||
m.s[cfsVars].add typeEntry
|
||||
else:
|
||||
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
|
||||
m.s[cfsVars].add typeEntry
|
||||
|
||||
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
|
||||
discard genTypeInfoV1(m, t, info)
|
||||
@@ -1786,9 +1824,9 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
|
||||
result = prefixTI.rope & result & ")".rope
|
||||
|
||||
proc openArrayToTuple(m: BModule; t: PType): PType =
|
||||
result = newType(tyTuple, nextTypeId m.idgen, t.owner)
|
||||
let p = newType(tyPtr, nextTypeId m.idgen, t.owner)
|
||||
let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner)
|
||||
result = newType(tyTuple, m.idgen, t.owner)
|
||||
let p = newType(tyPtr, m.idgen, t.owner)
|
||||
let a = newType(tyUncheckedArray, m.idgen, t.owner)
|
||||
a.add t.lastSon
|
||||
p.add a
|
||||
result.add p
|
||||
@@ -1928,14 +1966,14 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
|
||||
else:
|
||||
result = genTypeInfoV1(m, t, info)
|
||||
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
var intSet = initIntSet()
|
||||
for i in 0..<n.len:
|
||||
if len(n[i]) == 0: continue
|
||||
if n[i][0].kind != nkPragmaExpr: continue
|
||||
for p in 0..<n[i][0].len:
|
||||
if (n[i][0][p].kind != nkSym): continue
|
||||
if sfExportc in n[i][0][p].sym.flags:
|
||||
if sfExportc in n[i][0][p].sym.flags:
|
||||
discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
|
||||
if m.g.generatedHeader != nil:
|
||||
discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
# This module declares some helpers for the C code generator.
|
||||
|
||||
import
|
||||
ast, types, hashes, strutils, msgs, wordrecg,
|
||||
ast, types, msgs, wordrecg,
|
||||
platform, trees, options, cgendata
|
||||
|
||||
import std/[hashes, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
## This module implements the C code generator.
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||
ast, astalgo, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
|
||||
ccgutils, ropes, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
|
||||
lowerings, ndi, lineinfos, pathutils, transf,
|
||||
injectdestructors, astmsgs, modulepaths, backendpragmas
|
||||
|
||||
from expanddefaults import caseObjDefaultBranch
|
||||
|
||||
import pipelineutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -25,10 +27,10 @@ when defined(nimPreviewSlimSystem):
|
||||
when not defined(leanCompiler):
|
||||
import spawn, semparallel
|
||||
|
||||
import strutils except `%`, addf # collides with ropes.`%`
|
||||
import std/strutils except `%`, addf # collides with ropes.`%`
|
||||
|
||||
from ic / ic import ModuleBackendFlag
|
||||
import dynlib
|
||||
import std/[dynlib, math, tables, sets, os, intsets, hashes]
|
||||
|
||||
when not declared(dynlib.libCandidates):
|
||||
proc libCandidates(s: string, dest: var seq[string]) =
|
||||
@@ -119,7 +121,7 @@ proc getModuleDllPath(m: BModule, module: int): Rope =
|
||||
proc getModuleDllPath(m: BModule, s: PSym): Rope =
|
||||
result = getModuleDllPath(m.g.modules[s.itemId.module])
|
||||
|
||||
import macros
|
||||
import std/macros
|
||||
|
||||
proc cgFormatValue(result: var string; value: string) =
|
||||
result.add value
|
||||
@@ -364,6 +366,8 @@ proc dataField(p: BProc): Rope =
|
||||
else:
|
||||
result = rope"->data"
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
|
||||
include ccgliterals
|
||||
include ccgtypes
|
||||
|
||||
@@ -551,7 +555,8 @@ proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
|
||||
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
|
||||
storage: OnStack, flags: {})
|
||||
if p.module.compileToCpp and isOrHasImportedCppType(t):
|
||||
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.r,
|
||||
genCppInitializer(p.module, p, t)])
|
||||
else:
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
|
||||
constructLoc(p, result, not needsInit)
|
||||
@@ -606,7 +611,10 @@ proc assignLocalVar(p: BProc, n: PNode) =
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let nl = if optLineDir in p.config.options: "" else: "\n"
|
||||
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
|
||||
var decl = localVarDecl(p, n)
|
||||
if p.module.compileToCpp and isOrHasImportedCppType(n.typ):
|
||||
decl.add genCppInitializer(p.module, p, n.typ)
|
||||
decl.add ";" & nl
|
||||
line(p, cpsLocals, decl)
|
||||
|
||||
include ccgthreadvars
|
||||
@@ -640,7 +648,7 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
|
||||
else:
|
||||
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
|
||||
|
||||
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
|
||||
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope)
|
||||
|
||||
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
|
||||
let s = vn.sym
|
||||
@@ -650,7 +658,7 @@ proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
|
||||
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
|
||||
genGlobalVarDecl(p, vn, td, "", decl)
|
||||
decl.add " " & $s.loc.r
|
||||
genCppVarForCtor(p, v, vn, value, decl)
|
||||
genCppVarForCtor(p, value, decl)
|
||||
p.module.s[cfsVars].add decl
|
||||
|
||||
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||
@@ -728,7 +736,7 @@ proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
proc genStmts(p: BProc, t: PNode)
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||
proc intLiteral(i: BiggestInt; result: var Rope)
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Rope)
|
||||
@@ -1156,7 +1164,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
var procBody = transformBody(m.g.graph, m.idgen, prc, dontUseCache)
|
||||
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
|
||||
if sfInjectDestructors in prc.flags:
|
||||
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
|
||||
|
||||
@@ -1187,12 +1195,8 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
elif sfConstructor in prc.flags:
|
||||
resNode.sym.loc.flags.incl lfIndirect
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
let ty = resNode.sym.typ[0] #generate nim's ctor
|
||||
for i in 1..<resNode.sym.ast.len:
|
||||
let field = resNode.sym.ast[i]
|
||||
genFieldObjConstr(p, ty, useTemp = false, isRef = false,
|
||||
field[0], field[1], check = nil, resNode.sym.loc, "(*this)", tmpInfo)
|
||||
else:
|
||||
fillResult(p.config, resNode, prc.typ)
|
||||
assignParam(p, res, prc.typ[0])
|
||||
@@ -2179,9 +2183,8 @@ proc updateCachedModule(m: BModule) =
|
||||
cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
|
||||
## Also called from IC.
|
||||
result = nil
|
||||
if sfMainModule in m.module.flags:
|
||||
# phase ordering problem here: We need to announce this
|
||||
# dependency to 'nimTestErrorFlag' before system.c has been written to disk.
|
||||
@@ -2229,7 +2232,11 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
|
||||
if m.g.forwardedProcs.len == 0:
|
||||
incl m.flags, objHasKidsValid
|
||||
result = generateMethodDispatchers(graph, m.idgen)
|
||||
if optMultiMethods in m.g.config.globalOptions or
|
||||
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or
|
||||
vtables notin m.g.config.features:
|
||||
generateIfMethodDispatchers(graph, m.idgen)
|
||||
|
||||
|
||||
let mm = m
|
||||
m.g.modulesClosed.add mm
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
## This module contains the data structures for the C code generation phase.
|
||||
|
||||
import
|
||||
ast, ropes, options, intsets,
|
||||
tables, ndi, lineinfos, pathutils, modulegraphs, sets
|
||||
ast, ropes, options,
|
||||
ndi, lineinfos, pathutils, modulegraphs
|
||||
|
||||
import std/[intsets, tables, sets]
|
||||
|
||||
type
|
||||
TLabel* = Rope # for the C generator a label is just a rope
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
## This module implements code generation for methods.
|
||||
|
||||
import
|
||||
intsets, options, ast, msgs, idents, renderer, types, magicsys,
|
||||
sempass2, modulegraphs, lineinfos
|
||||
options, ast, msgs, idents, renderer, types, magicsys,
|
||||
sempass2, modulegraphs, lineinfos, astalgo
|
||||
|
||||
import std/intsets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import std/[tables]
|
||||
|
||||
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
|
||||
var dest = skipTypes(d, abstractPtrs)
|
||||
@@ -98,7 +101,8 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
|
||||
return No
|
||||
if result == Yes:
|
||||
# check for return type:
|
||||
if not sameTypeOrNil(a.typ[0], b.typ[0]):
|
||||
# ignore flags of return types; # bug #22673
|
||||
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
|
||||
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
|
||||
# infer 'auto' from the base to make it consistent:
|
||||
b.typ[0] = a.typ[0]
|
||||
@@ -120,7 +124,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
|
||||
incl(disp.flags, sfDispatcher)
|
||||
excl(disp.flags, sfExported)
|
||||
let old = disp.typ
|
||||
disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner)
|
||||
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
|
||||
copyTypeProps(g, idgen.module, disp.typ, old)
|
||||
|
||||
# we can't inline the dispatcher itself (for now):
|
||||
@@ -153,6 +157,9 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
|
||||
|
||||
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
var witness: PSym = nil
|
||||
if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"):
|
||||
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
|
||||
"` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")")
|
||||
for i in 0..<g.methods.len:
|
||||
let disp = g.methods[i].dispatcher
|
||||
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
|
||||
@@ -171,6 +178,11 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
of Invalid:
|
||||
if witness.isNil: witness = g.methods[i].methods[0]
|
||||
# create a new dispatcher:
|
||||
# stores the id and the position
|
||||
if s.typ[1].skipTypes(skipPtrs).itemId notin g.bucketTable:
|
||||
g.bucketTable[s.typ[1].skipTypes(skipPtrs).itemId] = 1
|
||||
else:
|
||||
g.bucketTable.inc(s.typ[1].skipTypes(skipPtrs).itemId)
|
||||
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
|
||||
#echo "adding ", s.info
|
||||
if witness != nil:
|
||||
@@ -179,7 +191,7 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
|
||||
elif sfBase notin s.flags:
|
||||
message(g.config, s.info, warnUseBase)
|
||||
|
||||
proc relevantCol(methods: seq[PSym], col: int): bool =
|
||||
proc relevantCol*(methods: seq[PSym], col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
result = false
|
||||
var t = methods[0].typ[col].skipTypes(skipPtrs)
|
||||
@@ -199,7 +211,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
if (d != high(int)) and d != 0:
|
||||
return d
|
||||
|
||||
proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
|
||||
proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
|
||||
# we use shellsort here; fast and simple
|
||||
var n = a.len
|
||||
var h = 1
|
||||
@@ -218,7 +230,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
|
||||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
|
||||
proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
|
||||
var base = methods[0].ast[dispatcherPos].sym
|
||||
result = base
|
||||
var paramLen = base.typ.len
|
||||
@@ -277,8 +289,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idg
|
||||
nilchecks.flags.incl nfTransf # should not be further transformed
|
||||
result.ast[bodyPos] = nilchecks
|
||||
|
||||
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
|
||||
for bucket in 0..<g.methods.len:
|
||||
var relevantCols = initIntSet()
|
||||
for col in 1..<g.methods[bucket].methods[0].typ.len:
|
||||
@@ -287,4 +298,4 @@ proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
|
||||
# if multi-methods are not enabled, we are interested only in the first field
|
||||
break
|
||||
sortBucket(g.methods[bucket].methods, relevantCols)
|
||||
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))
|
||||
g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, idgen)
|
||||
|
||||
@@ -134,7 +134,9 @@
|
||||
import
|
||||
ast, msgs, idents,
|
||||
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
|
||||
tables, options
|
||||
options
|
||||
|
||||
import std/tables
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -1158,9 +1160,9 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
|
||||
n[i] = ctx.skipThroughEmptyStates(n[i])
|
||||
|
||||
proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: PSym): PType =
|
||||
result = newType(tyArray, nextTypeId(idgen), owner)
|
||||
result = newType(tyArray, idgen, owner)
|
||||
|
||||
let rng = newType(tyRange, nextTypeId(idgen), owner)
|
||||
let rng = newType(tyRange, idgen, owner)
|
||||
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
|
||||
rng.rawAddSon(t)
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
import
|
||||
options, idents, nimconf, extccomp, commands, msgs,
|
||||
lineinfos, modulegraphs, condsyms, os, pathutils, parseopt
|
||||
lineinfos, modulegraphs, condsyms, pathutils
|
||||
|
||||
import std/[os, parseopt]
|
||||
|
||||
proc prependCurDir*(f: AbsoluteFile): AbsoluteFile =
|
||||
when defined(unix):
|
||||
|
||||
@@ -27,7 +27,9 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs]
|
||||
import
|
||||
msgs, options, nversion, condsyms, extccomp, platform,
|
||||
wordrecg, nimblecmd, lineinfos, pathutils, pathnorm
|
||||
wordrecg, nimblecmd, lineinfos, pathutils
|
||||
|
||||
import std/pathnorm
|
||||
|
||||
from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect
|
||||
|
||||
@@ -205,7 +207,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
|
||||
let x = findStr(noteMin, noteMax, id, errUnknown)
|
||||
if x != errUnknown: notes = {TNoteKind(x)}
|
||||
else: localError(conf, info, "unknown $#: $#" % [name, id])
|
||||
else:
|
||||
if isSomeHint:
|
||||
message(conf, info, hintUnknownHint, id)
|
||||
else:
|
||||
localError(conf, info, "unknown $#: $#" % [name, id])
|
||||
case id.normalize
|
||||
of "all": # other note groups would be easy to support via additional cases
|
||||
notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}
|
||||
@@ -456,10 +462,12 @@ proc handleCmdInput*(conf: ConfigRef) =
|
||||
proc parseCommand*(command: string): Command =
|
||||
case command.normalize
|
||||
of "c", "cc", "compile", "compiletoc": cmdCompileToC
|
||||
of "nir": cmdCompileToNir
|
||||
of "cpp", "compiletocpp": cmdCompileToCpp
|
||||
of "objc", "compiletooc": cmdCompileToOC
|
||||
of "js", "compiletojs": cmdCompileToJS
|
||||
of "r": cmdCrun
|
||||
of "m": cmdM
|
||||
of "run": cmdTcc
|
||||
of "check": cmdCheck
|
||||
of "e": cmdNimscript
|
||||
@@ -492,6 +500,7 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
|
||||
of cmdCompileToCpp: conf.backend = backendCpp
|
||||
of cmdCompileToOC: conf.backend = backendObjc
|
||||
of cmdCompileToJS: conf.backend = backendJs
|
||||
of cmdCompileToNir: conf.backend = backendNir
|
||||
else: discard
|
||||
|
||||
proc setCommandEarly*(conf: ConfigRef, command: string) =
|
||||
@@ -604,6 +613,13 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
defineSymbol(conf.symbols, "gcregions")
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
|
||||
proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): string =
|
||||
if pass == passPP and not isAbsolute(arg):
|
||||
assert isAbsolute(conf.currentConfigDir), "something is wrong with currentConfigDir"
|
||||
result = conf.currentConfigDir / arg
|
||||
else:
|
||||
result = arg
|
||||
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
conf: ConfigRef) =
|
||||
var key = ""
|
||||
@@ -649,7 +665,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
# refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set
|
||||
# in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")`
|
||||
if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/')
|
||||
conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true)
|
||||
conf.nimcacheDir = processPath(conf, pathRelativeToConfig(arg, pass, conf), info, notRelativeToProj=true)
|
||||
of "out", "o":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string)
|
||||
@@ -783,7 +799,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
|
||||
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
|
||||
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
|
||||
of "tlsemulation":
|
||||
of "tlsemulation":
|
||||
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
|
||||
if optTlsEmulation in conf.globalOptions:
|
||||
conf.legacyFeatures.incl emitGenerics
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
## for details. Note this is a first implementation and only the "Concept matching"
|
||||
## section has been implemented.
|
||||
|
||||
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets
|
||||
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types
|
||||
|
||||
import std/intsets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -26,9 +28,9 @@ proc declareSelf(c: PContext; info: TLineInfo) =
|
||||
## Adds the magical 'Self' symbols to the current scope.
|
||||
let ow = getCurrOwner(c)
|
||||
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
|
||||
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
|
||||
s.typ = newType(tyTypeDesc, c.idgen, ow)
|
||||
s.typ.flags.incl {tfUnresolved, tfPacked}
|
||||
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
|
||||
s.typ.add newType(tyEmpty, c.idgen, ow)
|
||||
addDecl(c, s, info)
|
||||
|
||||
proc semConceptDecl(c: PContext; n: PNode): PNode =
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module handles the conditional symbols.
|
||||
|
||||
import
|
||||
strtabs
|
||||
std/strtabs
|
||||
|
||||
from options import Feature
|
||||
from lineinfos import hintMin, hintMax, warnMin, warnMax
|
||||
@@ -143,7 +143,6 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||
defineSymbol("nimHasCstringCase")
|
||||
defineSymbol("nimHasCallsitePragma")
|
||||
defineSymbol("nimHasAmbiguousEnumHint")
|
||||
|
||||
defineSymbol("nimHasWarnCastSizes") # deadcode
|
||||
defineSymbol("nimHasOutParams")
|
||||
@@ -162,3 +161,8 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimUseStrictDefs")
|
||||
defineSymbol("nimHasNolineTooLong")
|
||||
defineSymbol("nimHasQuirkyBoots")
|
||||
|
||||
defineSymbol("nimHasCastExtendedVm")
|
||||
defineSymbol("nimHasWarnStdPrefix")
|
||||
|
||||
defineSymbol("nimHasVtables")
|
||||
|
||||
@@ -14,7 +14,7 @@ import options, ast, ropes, pathutils, msgs, lineinfos
|
||||
import modulegraphs
|
||||
|
||||
import std/[os, parseutils]
|
||||
import strutils except addf
|
||||
import std/strutils except addf
|
||||
import std/private/globs
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
|
||||
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
|
||||
|
||||
import ast, intsets, lineinfos, renderer, aliasanalysis
|
||||
import ast, lineinfos, renderer, aliasanalysis
|
||||
import std/private/asciitables
|
||||
import std/intsets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -129,10 +130,6 @@ template withBlock(labl: PSym; body: untyped) =
|
||||
body
|
||||
popBlock(c, oldLen)
|
||||
|
||||
proc isTrue(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
|
||||
n.kind == nkIntLit and n.intVal != 0
|
||||
|
||||
template forkT(body) =
|
||||
let lab1 = c.forkI()
|
||||
body
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
## For corresponding users' documentation see [Nim DocGen Tools Guide].
|
||||
|
||||
import
|
||||
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
|
||||
ast, options, msgs, idents,
|
||||
wordrecg, syntaxes, renderer, lexer,
|
||||
packages/docutils/[rst, rstidx, rstgen, dochelpers],
|
||||
json, xmltree, trees, types,
|
||||
typesrenderer, astalgo, lineinfos, intsets,
|
||||
pathutils, tables, nimpaths, renderverbatim, osproc, packages
|
||||
trees, types,
|
||||
typesrenderer, astalgo, lineinfos,
|
||||
pathutils, nimpaths, renderverbatim, packages
|
||||
import packages/docutils/rstast except FileIndex, TLineInfo
|
||||
|
||||
from uri import encodeUrl
|
||||
import std/[os, strutils, strtabs, algorithm, json, osproc, tables, intsets, xmltree, sequtils]
|
||||
from std/uri import encodeUrl
|
||||
from nodejs import findNodeJs
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -1805,7 +1806,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
|
||||
"moduleDescription": modDesc,
|
||||
"entries": d.jEntriesFinal}
|
||||
if optStdout in d.conf.globalOptions:
|
||||
write(stdout, $content)
|
||||
writeLine(stdout, $content)
|
||||
else:
|
||||
let dir = d.destFile.splitFile.dir
|
||||
createDir(dir)
|
||||
|
||||
@@ -14,7 +14,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyString)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
result.typ = newType(tyProc, idgen, t.owner)
|
||||
result.typ.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result.typ, res.typ)
|
||||
result.typ.n.add newNodeI(nkEffectList, info)
|
||||
@@ -76,7 +76,7 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
|
||||
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
|
||||
res.typ = getSysType(g, info, tyUInt8)
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
|
||||
result.typ = newType(tyProc, idgen, t.owner)
|
||||
result.typ.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result.typ, res.typ)
|
||||
result.typ.n.add newNodeI(nkEffectList, info)
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
## This module contains support code for new-styled error
|
||||
## handling via an `nkError` node kind.
|
||||
|
||||
import ast, renderer, options, strutils, types
|
||||
import ast, renderer, options, types
|
||||
import std/strutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -40,7 +41,8 @@ proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
|
||||
let innerError = errorSubNode(wrongNode)
|
||||
if innerError != nil:
|
||||
return innerError
|
||||
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
|
||||
var idgen = idGeneratorForPackage(-1'i32)
|
||||
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
|
||||
result.add wrongNode
|
||||
result.add newIntNode(nkIntLit, ord(k))
|
||||
for a in args: result.add a
|
||||
@@ -50,7 +52,8 @@ proc newError*(wrongNode: PNode; msg: string): PNode =
|
||||
let innerError = errorSubNode(wrongNode)
|
||||
if innerError != nil:
|
||||
return innerError
|
||||
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
|
||||
var idgen = idGeneratorForPackage(-1'i32)
|
||||
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
|
||||
result.add wrongNode
|
||||
result.add newIntNode(nkIntLit, ord(CustomError))
|
||||
result.add newStrNode(msg, wrongNode.info)
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
## This file implements the FFI part of the evaluator for Nim code.
|
||||
|
||||
import ast, types, options, tables, dynlib, msgs, lineinfos
|
||||
from os import getAppFilename
|
||||
import ast, types, options, msgs, lineinfos
|
||||
from std/os import getAppFilename
|
||||
import libffi/libffi
|
||||
|
||||
import std/[tables, dynlib]
|
||||
|
||||
when defined(windows):
|
||||
const libcDll = "msvcrt.dll"
|
||||
elif defined(linux):
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
|
||||
import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
|
||||
import std/strutils
|
||||
|
||||
type
|
||||
TemplCtx = object
|
||||
|
||||
131
compiler/expanddefaults.nim
Normal file
131
compiler/expanddefaults.nim
Normal file
@@ -0,0 +1,131 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import lineinfos, ast, types
|
||||
|
||||
proc caseObjDefaultBranch*(obj: PNode; branch: Int128): int =
|
||||
result = 0
|
||||
for i in 1 ..< obj.len:
|
||||
for j in 0 .. obj[i].len - 2:
|
||||
if obj[i][j].kind == nkRange:
|
||||
let x = getOrdValue(obj[i][j][0])
|
||||
let y = getOrdValue(obj[i][j][1])
|
||||
if branch >= x and branch <= y:
|
||||
return i
|
||||
elif getOrdValue(obj[i][j]) == branch:
|
||||
return i
|
||||
if obj[i].len == 1:
|
||||
# else branch
|
||||
return i
|
||||
return 1
|
||||
|
||||
template newZero(t: PType; info: TLineInfo; k = nkIntLit): PNode = newNodeIT(k, info, t)
|
||||
|
||||
proc expandDefault*(t: PType; info: TLineInfo): PNode
|
||||
|
||||
proc expandField(s: PSym; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkExprColonExpr, info, s.typ)
|
||||
result.add newSymNode(s)
|
||||
result.add expandDefault(s.typ, info)
|
||||
|
||||
proc expandDefaultN(n: PNode; info: TLineInfo; res: PNode) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
expandDefaultN(n[i], info, res)
|
||||
of nkRecCase:
|
||||
res.add expandField(n[0].sym, info)
|
||||
var branch = Zero
|
||||
let constOrNil = n[0].sym.astdef
|
||||
if constOrNil != nil:
|
||||
branch = getOrdValue(constOrNil)
|
||||
|
||||
let selectedBranch = caseObjDefaultBranch(n, branch)
|
||||
let b = lastSon(n[selectedBranch])
|
||||
expandDefaultN b, info, res
|
||||
of nkSym:
|
||||
res.add expandField(n.sym, info)
|
||||
else:
|
||||
discard
|
||||
|
||||
proc expandDefaultObj(t: PType; info: TLineInfo; res: PNode) =
|
||||
if t[0] != nil:
|
||||
expandDefaultObj(t[0], info, res)
|
||||
expandDefaultN(t.n, info, res)
|
||||
|
||||
proc expandDefault(t: PType; info: TLineInfo): PNode =
|
||||
case t.kind
|
||||
of tyInt: result = newZero(t, info, nkIntLit)
|
||||
of tyInt8: result = newZero(t, info, nkInt8Lit)
|
||||
of tyInt16: result = newZero(t, info, nkInt16Lit)
|
||||
of tyInt32: result = newZero(t, info, nkInt32Lit)
|
||||
of tyInt64: result = newZero(t, info, nkInt64Lit)
|
||||
of tyUInt: result = newZero(t, info, nkUIntLit)
|
||||
of tyUInt8: result = newZero(t, info, nkUInt8Lit)
|
||||
of tyUInt16: result = newZero(t, info, nkUInt16Lit)
|
||||
of tyUInt32: result = newZero(t, info, nkUInt32Lit)
|
||||
of tyUInt64: result = newZero(t, info, nkUInt64Lit)
|
||||
of tyFloat: result = newZero(t, info, nkFloatLit)
|
||||
of tyFloat32: result = newZero(t, info, nkFloat32Lit)
|
||||
of tyFloat64: result = newZero(t, info, nkFloat64Lit)
|
||||
of tyFloat128: result = newZero(t, info, nkFloat64Lit)
|
||||
of tyChar: result = newZero(t, info, nkCharLit)
|
||||
of tyBool: result = newZero(t, info, nkIntLit)
|
||||
of tyEnum:
|
||||
# Could use low(T) here to finally fix old language quirks
|
||||
result = newZero(t, info, nkIntLit)
|
||||
of tyRange:
|
||||
# Could use low(T) here to finally fix old language quirks
|
||||
result = expandDefault(t[0], info)
|
||||
of tyVoid: result = newZero(t, info, nkEmpty)
|
||||
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned:
|
||||
result = expandDefault(t.lastSon, info)
|
||||
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
|
||||
if t.len > 0:
|
||||
result = expandDefault(t.lastSon, info)
|
||||
else:
|
||||
result = newZero(t, info, nkEmpty)
|
||||
of tyFromExpr:
|
||||
if t.n != nil and t.n.typ != nil:
|
||||
result = expandDefault(t.n.typ, info)
|
||||
else:
|
||||
result = newZero(t, info, nkEmpty)
|
||||
of tyArray:
|
||||
result = newZero(t, info, nkBracket)
|
||||
let n = toInt64(lengthOrd(nil, t))
|
||||
for i in 0..<n:
|
||||
result.add expandDefault(t[1], info)
|
||||
of tyPtr, tyRef, tyProc, tyPointer, tyCstring:
|
||||
result = newZero(t, info, nkNilLit)
|
||||
of tyVar, tyLent:
|
||||
let e = t.lastSon
|
||||
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
# skip the modifier, `var openArray` is a (ptr, len) pair too:
|
||||
result = expandDefault(e, info)
|
||||
else:
|
||||
result = newZero(t.lastSon, info, nkNilLit)
|
||||
of tySet:
|
||||
result = newZero(t, info, nkCurly)
|
||||
of tyObject:
|
||||
result = newNodeIT(nkObjConstr, info, t)
|
||||
result.add newNodeIT(nkType, info, t)
|
||||
expandDefaultObj(t, info, result)
|
||||
of tyTuple:
|
||||
result = newZero(t, info, nkTupleConstr)
|
||||
for it in t:
|
||||
result.add expandDefault(it, info)
|
||||
of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray:
|
||||
result = newZero(t, info, nkBracket)
|
||||
of tyString:
|
||||
result = newZero(t, info, nkStrLit)
|
||||
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
|
||||
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
|
||||
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
|
||||
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
|
||||
result = newZero(t, info, nkEmpty) # bug indicator
|
||||
@@ -33,6 +33,7 @@ type
|
||||
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
|
||||
hasDeclspec, # CC has __declspec(X)
|
||||
hasAttribute, # CC has __attribute__((X))
|
||||
hasBuiltinUnreachable # CC has __builtin_unreachable
|
||||
TInfoCCProps* = set[TInfoCCProp]
|
||||
TInfoCC* = tuple[
|
||||
name: string, # the short name of the compiler
|
||||
@@ -95,7 +96,7 @@ compiler gcc:
|
||||
produceAsm: gnuAsmListing,
|
||||
cppXsupport: "-std=gnu++17 -funsigned-char",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasAttribute})
|
||||
hasAttribute, hasBuiltinUnreachable})
|
||||
|
||||
# GNU C and C++ Compiler
|
||||
compiler nintendoSwitchGCC:
|
||||
@@ -122,7 +123,7 @@ compiler nintendoSwitchGCC:
|
||||
produceAsm: gnuAsmListing,
|
||||
cppXsupport: "-std=gnu++17 -funsigned-char",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasAttribute})
|
||||
hasAttribute, hasBuiltinUnreachable})
|
||||
|
||||
# LLVM Frontend for GCC/G++
|
||||
compiler llvmGcc:
|
||||
@@ -318,7 +319,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
var fullSuffix = suffix
|
||||
case conf.backend
|
||||
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
|
||||
of backendC: discard
|
||||
of backendC, backendNir: discard
|
||||
of backendInvalid:
|
||||
# during parsing of cfg files; we don't know the backend yet, no point in
|
||||
# guessing wrong thing
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
# This module implements Nim's standard template filter.
|
||||
|
||||
import
|
||||
llstream, strutils, ast, msgs, options,
|
||||
llstream, ast, msgs, options,
|
||||
filters, lineinfos, pathutils
|
||||
|
||||
import std/strutils
|
||||
|
||||
type
|
||||
TParseState = enum
|
||||
psDirective, psTempl
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
# This module implements Nim's simple filters and helpers for filters.
|
||||
|
||||
import
|
||||
llstream, idents, strutils, ast, msgs, options,
|
||||
llstream, idents, ast, msgs, options,
|
||||
renderer, pathutils
|
||||
|
||||
import std/strutils
|
||||
|
||||
proc invalidPragma(conf: ConfigRef; n: PNode) =
|
||||
localError(conf, n.info,
|
||||
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
## Module that implements ``gorge`` for the compiler.
|
||||
|
||||
import msgs, os, osproc, streams, options,
|
||||
lineinfos, pathutils
|
||||
import msgs, options, lineinfos, pathutils
|
||||
|
||||
import std/[os, osproc, streams]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
|
||||
@@ -870,7 +870,7 @@ template isSub(x): untyped = x.getMagic in someSub
|
||||
template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit}
|
||||
template isIntVal(x, y): untyped = x.intVal == y
|
||||
|
||||
import macros
|
||||
import std/macros
|
||||
|
||||
macro `=~`(x: PNode, pat: untyped): bool =
|
||||
proc m(x, pat, conds: NimNode) =
|
||||
@@ -1098,8 +1098,8 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
|
||||
addFactLe(m, a, bb)
|
||||
|
||||
proc settype(n: PNode): PType =
|
||||
result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
|
||||
var idgen: IdGenerator = nil
|
||||
var idgen = idGeneratorForPackage(-1'i32)
|
||||
result = newType(tySet, idgen, n.typ.owner)
|
||||
addSonSkipIntLit(result, n.typ, idgen)
|
||||
|
||||
proc buildOf(it, loc: PNode; o: Operators): PNode =
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
## A BiTable is a table that can be seen as an optimized pair
|
||||
## of `(Table[LitId, Val], Table[Val, LitId])`.
|
||||
|
||||
import hashes, rodfiles
|
||||
import std/hashes
|
||||
import rodfiles
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -13,6 +14,8 @@ type
|
||||
vals: seq[T] # indexed by LitId
|
||||
keys: seq[LitId] # indexed by hash(val)
|
||||
|
||||
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
|
||||
|
||||
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
|
||||
result = (h + 1) and maxHash
|
||||
|
||||
@@ -33,9 +36,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
const
|
||||
idStart = 256 ##
|
||||
## Ids do not start with 0 but with this value. The IR needs it.
|
||||
## TODO: explain why
|
||||
idStart = 1
|
||||
|
||||
template idToIdx(x: LitId): int = x.int - idStart
|
||||
|
||||
@@ -118,6 +119,12 @@ proc load*[T](f: var RodFile; t: var BiTable[T]) =
|
||||
loadSeq(f, t.vals)
|
||||
loadSeq(f, t.keys)
|
||||
|
||||
proc sizeOnDisc*(t: BiTable[string]): int =
|
||||
result = 4
|
||||
for x in t.vals:
|
||||
result += x.len + 4
|
||||
result += t.keys.len * sizeof(LitId)
|
||||
|
||||
when isMainModule:
|
||||
|
||||
var t: BiTable[string]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
## also doing cross-module dependency tracking and DCE that we don't need
|
||||
## anymore. DCE is now done as prepass over the entire packed module graph.
|
||||
|
||||
import std/packedsets, algorithm, tables
|
||||
import std/[packedsets, algorithm, tables]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -50,10 +50,9 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
|
||||
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
|
||||
cgen.genTopLevelStmt(bmod, n)
|
||||
|
||||
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
if disps != nil:
|
||||
for disp in disps:
|
||||
genProcAux(bmod, disp.sym)
|
||||
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
|
||||
for disp in getDispatchers(g):
|
||||
genProcAux(bmod, disp)
|
||||
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
|
||||
|
||||
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
|
||||
@@ -147,12 +146,12 @@ proc generateCode*(g: ModuleGraph) =
|
||||
var alive = computeAliveSyms(g.packed, g.config)
|
||||
|
||||
when false:
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
|
||||
|
||||
# First pass: Setup all the backend modules for all the modules that have
|
||||
# changed:
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
@@ -174,7 +173,7 @@ proc generateCode*(g: ModuleGraph) =
|
||||
let mainModuleIdx = g.config.projectMainIdx2.int
|
||||
# We need to generate the main module last, because only then
|
||||
# all init procs have been registered:
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
if i != mainModuleIdx:
|
||||
genPackedModule(g, i, alive)
|
||||
if mainModuleIdx >= 0:
|
||||
|
||||
@@ -109,13 +109,13 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
|
||||
discard "ignore non-sym atoms"
|
||||
of nkSym:
|
||||
# This symbol is alive and everything its body references.
|
||||
followLater(c, g, c.thisModule, n.operand)
|
||||
followLater(c, g, c.thisModule, tree[n].soperand)
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, n)
|
||||
assert n1.kind == nkInt32Lit
|
||||
assert n2.kind == nkInt32Lit
|
||||
assert n1.kind == nkNone
|
||||
assert n2.kind == nkNone
|
||||
let m = n1.litId
|
||||
let item = n2.operand
|
||||
let item = tree[n2].soperand
|
||||
let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
|
||||
followLater(c, g, otherModule, item)
|
||||
of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
|
||||
@@ -131,7 +131,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
|
||||
rangeCheckAnalysis(c, g, tree, n)
|
||||
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
|
||||
if n.firstSon.kind == nkSym and isNotGeneric(n):
|
||||
let item = n.firstSon.operand
|
||||
let item = tree[n.firstSon].soperand
|
||||
if isExportedToC(c, g, item):
|
||||
# This symbol is alive and everything its body references.
|
||||
followLater(c, g, c.thisModule, item)
|
||||
@@ -153,7 +153,7 @@ proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
|
||||
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
|
||||
thisModule: -1, alive: newSeq[IntSet](g.len),
|
||||
options: conf.options)
|
||||
for i in countdown(high(g), 0):
|
||||
for i in countdown(len(g)-1, 0):
|
||||
if g[i].status != undefined:
|
||||
c.thisModule = i
|
||||
for p in allNodes(g[i].fromDisk.topLevel):
|
||||
|
||||
@@ -7,15 +7,17 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import hashes, tables, intsets
|
||||
import std/[hashes, tables, intsets, monotimes]
|
||||
import packed_ast, bitabs, rodfiles
|
||||
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
|
||||
pathutils, condsyms, packages, modulepaths]
|
||||
#import ".." / [renderer, astalgo]
|
||||
from os import removeFile, isAbsolute
|
||||
from std/os import removeFile, isAbsolute
|
||||
|
||||
import ../../dist/checksums/src/checksums/sha1
|
||||
|
||||
import ".." / nir / nirlineinfos
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions, formatfloat]
|
||||
|
||||
@@ -41,16 +43,18 @@ type
|
||||
bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
|
||||
#producedGenerics*: Table[GenericKey, SymId]
|
||||
exports*: seq[(LitId, int32)]
|
||||
hidden*: seq[(LitId, int32)]
|
||||
reexports*: seq[(LitId, PackedItemId)]
|
||||
hidden: seq[(LitId, int32)]
|
||||
reexports: seq[(LitId, PackedItemId)]
|
||||
compilerProcs*: seq[(LitId, int32)]
|
||||
converters*, methods*, trmacros*, pureEnums*: seq[int32]
|
||||
|
||||
typeInstCache*: seq[(PackedItemId, PackedItemId)]
|
||||
procInstCache*: seq[PackedInstantiation]
|
||||
attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)]
|
||||
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
|
||||
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
|
||||
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
|
||||
methodsPerType*: seq[(PackedItemId, PackedItemId)]
|
||||
dispatchers*: seq[PackedItemId]
|
||||
|
||||
emittedTypeInfo*: seq[string]
|
||||
backendFlags*: set[ModuleBackendFlag]
|
||||
@@ -60,6 +64,7 @@ type
|
||||
strings*: BiTable[string] # we could share these between modules.
|
||||
numbers*: BiTable[BiggestInt] # we also store floats in here so
|
||||
# that we can assure that every bit is kept
|
||||
man*: LineInfoManager
|
||||
|
||||
cfg: PackedConfig
|
||||
|
||||
@@ -75,37 +80,36 @@ type
|
||||
symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
|
||||
config*: ConfigRef
|
||||
|
||||
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int;
|
||||
proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
|
||||
result: var string) =
|
||||
let pos = n.int
|
||||
if result.len > 0 and result[^1] notin {' ', '\n'}:
|
||||
result.add ' '
|
||||
|
||||
result.add $tree[pos].kind
|
||||
case tree.nodes[pos].kind
|
||||
of nkNone, nkEmpty, nkNilLit, nkType: discard
|
||||
case tree[pos].kind
|
||||
of nkEmpty, nkNilLit, nkType: discard
|
||||
of nkIdent, nkStrLit..nkTripleStrLit:
|
||||
result.add " "
|
||||
result.add m.strings[LitId tree.nodes[pos].operand]
|
||||
result.add m.strings[LitId tree[pos].uoperand]
|
||||
of nkSym:
|
||||
result.add " "
|
||||
result.add m.strings[m.syms[tree.nodes[pos].operand].name]
|
||||
result.add m.strings[m.syms[tree[pos].soperand].name]
|
||||
of directIntLit:
|
||||
result.add " "
|
||||
result.addInt tree.nodes[pos].operand
|
||||
result.addInt tree[pos].soperand
|
||||
of externSIntLit:
|
||||
result.add " "
|
||||
result.addInt m.numbers[LitId tree.nodes[pos].operand]
|
||||
result.addInt m.numbers[LitId tree[pos].uoperand]
|
||||
of externUIntLit:
|
||||
result.add " "
|
||||
result.addInt cast[uint64](m.numbers[LitId tree.nodes[pos].operand])
|
||||
result.addInt cast[uint64](m.numbers[LitId tree[pos].uoperand])
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
result.add " "
|
||||
result.addFloat cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand])
|
||||
result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].uoperand])
|
||||
else:
|
||||
result.add "(\n"
|
||||
for i in 1..(nesting+1)*2: result.add ' '
|
||||
for child in sonsReadonly(tree, n):
|
||||
for child in sonsReadonly(tree, pos):
|
||||
toString(tree, child, m, nesting + 1, result)
|
||||
result.add "\n"
|
||||
for i in 1..nesting*2: result.add ' '
|
||||
@@ -231,10 +235,14 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex)
|
||||
m.imports.add toLitId(f, c, m)
|
||||
|
||||
proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
|
||||
assert s.kind != skUnknown
|
||||
let nameId = getOrIncl(m.strings, s.name.s)
|
||||
m.hidden.add((nameId, s.itemId.item))
|
||||
assert s.itemId.module == c.thisModule
|
||||
|
||||
proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
|
||||
assert s.kind != skUnknown
|
||||
assert s.itemId.module == c.thisModule
|
||||
let nameId = getOrIncl(m.strings, s.name.s)
|
||||
m.exports.add((nameId, s.itemId.item))
|
||||
|
||||
@@ -253,6 +261,8 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
|
||||
m.methods.add s.itemId.item
|
||||
|
||||
proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
|
||||
assert s.kind != skUnknown
|
||||
if s.kind == skModule: return
|
||||
let nameId = getOrIncl(m.strings, s.name.s)
|
||||
m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
|
||||
item: s.itemId.item)))
|
||||
@@ -284,7 +294,8 @@ proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
|
||||
result = getOrIncl(m.numbers, x)
|
||||
|
||||
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
|
||||
PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
|
||||
pack(m.man, toLitId(x.fileIndex, c, m), x.line.int32, x.col.int32)
|
||||
#PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
|
||||
|
||||
proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} =
|
||||
## given a symbol, produce an ItemId with the correct properties
|
||||
@@ -336,7 +347,7 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed
|
||||
proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
|
||||
if s.isNil: return nilItemId
|
||||
assert s.itemId.module >= 0
|
||||
assert s.itemId.module >= 0
|
||||
assert s.itemId.item >= 0
|
||||
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
|
||||
if s.itemId.module == c.thisModule:
|
||||
# the sym belongs to this module, so serialize it here, eventually.
|
||||
@@ -421,53 +432,59 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
|
||||
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
|
||||
## add a remote symbol reference to the tree
|
||||
let info = n.info.toPackedInfo(c, m)
|
||||
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
|
||||
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
|
||||
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
|
||||
operand: n.sym.itemId.item)
|
||||
if n.typ != n.sym.typ:
|
||||
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
|
||||
info = info,
|
||||
typeId = storeTypeLater(n.typ, c, m))
|
||||
else:
|
||||
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
|
||||
info = info)
|
||||
ir.addNode(kind = nkNone, info = info,
|
||||
operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
|
||||
ir.addNode(kind = nkNone, info = info,
|
||||
operand = n.sym.itemId.item)
|
||||
|
||||
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
|
||||
## serialize a node into the tree
|
||||
if n == nil:
|
||||
ir.nodes.add PackedNode(kind: nkNilRodNode, flags: {}, operand: 1)
|
||||
ir.addNode(kind = nkNilRodNode, operand = 1, info = NoLineInfo)
|
||||
return
|
||||
let info = toPackedInfo(n.info, c, m)
|
||||
case n.kind
|
||||
of nkNone, nkEmpty, nkNilLit, nkType:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0,
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.addNode(kind = n.kind, flags = n.flags, operand = 0,
|
||||
typeId = storeTypeLater(n.typ, c, m), info = info)
|
||||
of nkIdent:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
|
||||
operand: int32 getOrIncl(m.strings, n.ident.s),
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.addNode(kind = n.kind, flags = n.flags,
|
||||
operand = int32 getOrIncl(m.strings, n.ident.s),
|
||||
typeId = storeTypeLater(n.typ, c, m), info = info)
|
||||
of nkSym:
|
||||
if n.sym.itemId.module == c.thisModule:
|
||||
# it is a symbol that belongs to the module we're currently
|
||||
# packing:
|
||||
let id = n.sym.storeSymLater(c, m).item
|
||||
ir.nodes.add PackedNode(kind: nkSym, flags: n.flags, operand: id,
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
if n.typ != n.sym.typ:
|
||||
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
|
||||
info = info,
|
||||
typeId = storeTypeLater(n.typ, c, m))
|
||||
else:
|
||||
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
|
||||
info = info)
|
||||
else:
|
||||
# store it as an external module reference:
|
||||
addModuleRef(n, ir, c, m)
|
||||
of directIntLit:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
|
||||
operand: int32(n.intVal),
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
of externIntLit:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
|
||||
operand: int32 getOrIncl(m.numbers, n.intVal),
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.addNode(kind = n.kind, flags = n.flags,
|
||||
operand = int32 getOrIncl(m.numbers, n.intVal),
|
||||
typeId = storeTypeLater(n.typ, c, m), info = info)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
|
||||
operand: int32 getOrIncl(m.strings, n.strVal),
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.addNode(kind = n.kind, flags = n.flags,
|
||||
operand = int32 getOrIncl(m.strings, n.strVal),
|
||||
typeId = storeTypeLater(n.typ, c, m), info = info)
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
|
||||
operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
|
||||
typeId: storeTypeLater(n.typ, c, m), info: info)
|
||||
ir.addNode(kind = n.kind, flags = n.flags,
|
||||
operand = int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
|
||||
typeId = storeTypeLater(n.typ, c, m), info = info)
|
||||
else:
|
||||
let patchPos = ir.prepare(n.kind, n.flags,
|
||||
storeTypeLater(n.typ, c, m), info)
|
||||
@@ -492,8 +509,8 @@ proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var
|
||||
# do not serialize the body of the proc, it's unnecessary since
|
||||
# n[0].sym.ast has the sem'checked variant of it which is what
|
||||
# everybody should use instead.
|
||||
ir.nodes.add PackedNode(kind: nkEmpty, flags: {}, operand: 0,
|
||||
typeId: nilItemId, info: info)
|
||||
ir.addNode(kind = nkEmpty, flags = {}, operand = 0,
|
||||
typeId = nilItemId, info = info)
|
||||
ir.patch patchPos
|
||||
|
||||
proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
|
||||
@@ -566,6 +583,20 @@ proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
|
||||
result = changeFileExt(completeGeneratedFilePath(conf,
|
||||
mangleModuleName(conf, f).AbsoluteFile), ext)
|
||||
|
||||
const
|
||||
BenchIC* = false
|
||||
|
||||
when BenchIC:
|
||||
var gloadBodies: MonoTime
|
||||
|
||||
template bench(x, body) =
|
||||
let start = getMonoTime()
|
||||
body
|
||||
x = x + (getMonoTime() - start)
|
||||
|
||||
else:
|
||||
template bench(x, body) = body
|
||||
|
||||
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
|
||||
ignoreConfig = false): RodFileError =
|
||||
var f = rodfiles.open(filename.string)
|
||||
@@ -590,40 +621,48 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
|
||||
loadTabSection stringsSection, m.strings
|
||||
|
||||
loadSeqSection checkSumsSection, m.includes
|
||||
if not includesIdentical(m, config):
|
||||
if config.cmd != cmdM and not includesIdentical(m, config):
|
||||
f.err = includeFileChanged
|
||||
|
||||
loadSeqSection depsSection, m.imports
|
||||
|
||||
loadTabSection numbersSection, m.numbers
|
||||
bench gloadBodies:
|
||||
|
||||
loadSeqSection exportsSection, m.exports
|
||||
loadSeqSection hiddenSection, m.hidden
|
||||
loadSeqSection reexportsSection, m.reexports
|
||||
loadTabSection numbersSection, m.numbers
|
||||
|
||||
loadSeqSection compilerProcsSection, m.compilerProcs
|
||||
loadSeqSection exportsSection, m.exports
|
||||
loadSeqSection hiddenSection, m.hidden
|
||||
loadSeqSection reexportsSection, m.reexports
|
||||
|
||||
loadSeqSection trmacrosSection, m.trmacros
|
||||
loadSeqSection compilerProcsSection, m.compilerProcs
|
||||
|
||||
loadSeqSection convertersSection, m.converters
|
||||
loadSeqSection methodsSection, m.methods
|
||||
loadSeqSection pureEnumsSection, m.pureEnums
|
||||
loadSeqSection trmacrosSection, m.trmacros
|
||||
|
||||
loadSeqSection toReplaySection, m.toReplay.nodes
|
||||
loadSeqSection topLevelSection, m.topLevel.nodes
|
||||
loadSeqSection bodiesSection, m.bodies.nodes
|
||||
loadSeqSection symsSection, m.syms
|
||||
loadSeqSection typesSection, m.types
|
||||
loadSeqSection convertersSection, m.converters
|
||||
loadSeqSection methodsSection, m.methods
|
||||
loadSeqSection pureEnumsSection, m.pureEnums
|
||||
|
||||
loadSeqSection typeInstCacheSection, m.typeInstCache
|
||||
loadSeqSection procInstCacheSection, m.procInstCache
|
||||
loadSeqSection attachedOpsSection, m.attachedOps
|
||||
loadSeqSection methodsPerTypeSection, m.methodsPerType
|
||||
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
|
||||
loadSeqSection typeInfoSection, m.emittedTypeInfo
|
||||
loadTabSection toReplaySection, m.toReplay
|
||||
loadTabSection topLevelSection, m.topLevel
|
||||
|
||||
f.loadSection backendFlagsSection
|
||||
f.loadPrim m.backendFlags
|
||||
loadTabSection bodiesSection, m.bodies
|
||||
loadSeqSection symsSection, m.syms
|
||||
loadSeqSection typesSection, m.types
|
||||
|
||||
loadSeqSection typeInstCacheSection, m.typeInstCache
|
||||
loadSeqSection procInstCacheSection, m.procInstCache
|
||||
loadSeqSection attachedOpsSection, m.attachedOps
|
||||
loadSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
|
||||
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
|
||||
loadSeqSection methodsPerTypeSection, m.methodsPerType
|
||||
loadSeqSection dispatchersSection, m.dispatchers
|
||||
loadSeqSection typeInfoSection, m.emittedTypeInfo
|
||||
|
||||
f.loadSection backendFlagsSection
|
||||
f.loadPrim m.backendFlags
|
||||
|
||||
f.loadSection sideChannelSection
|
||||
f.load m.man
|
||||
|
||||
close(f)
|
||||
result = f.err
|
||||
@@ -672,10 +711,10 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
|
||||
storeSeqSection methodsSection, m.methods
|
||||
storeSeqSection pureEnumsSection, m.pureEnums
|
||||
|
||||
storeSeqSection toReplaySection, m.toReplay.nodes
|
||||
storeSeqSection topLevelSection, m.topLevel.nodes
|
||||
storeTabSection toReplaySection, m.toReplay
|
||||
storeTabSection topLevelSection, m.topLevel
|
||||
|
||||
storeSeqSection bodiesSection, m.bodies.nodes
|
||||
storeTabSection bodiesSection, m.bodies
|
||||
storeSeqSection symsSection, m.syms
|
||||
|
||||
storeSeqSection typesSection, m.types
|
||||
@@ -683,13 +722,18 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
|
||||
storeSeqSection typeInstCacheSection, m.typeInstCache
|
||||
storeSeqSection procInstCacheSection, m.procInstCache
|
||||
storeSeqSection attachedOpsSection, m.attachedOps
|
||||
storeSeqSection methodsPerTypeSection, m.methodsPerType
|
||||
storeSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
|
||||
storeSeqSection enumToStringProcsSection, m.enumToStringProcs
|
||||
storeSeqSection methodsPerTypeSection, m.methodsPerType
|
||||
storeSeqSection dispatchersSection, m.dispatchers
|
||||
storeSeqSection typeInfoSection, m.emittedTypeInfo
|
||||
|
||||
f.storeSection backendFlagsSection
|
||||
f.storePrim m.backendFlags
|
||||
|
||||
f.storeSection sideChannelSection
|
||||
f.store m.man
|
||||
|
||||
close(f)
|
||||
encoder.disable()
|
||||
if f.err != ok:
|
||||
@@ -731,13 +775,29 @@ type
|
||||
# PackedItemId so that it works with reexported symbols too
|
||||
# ifaceHidden includes private symbols
|
||||
|
||||
PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex
|
||||
type
|
||||
PackedModuleGraph* = object
|
||||
pm*: seq[LoadedModule] # indexed by FileIndex
|
||||
when BenchIC:
|
||||
depAnalysis: MonoTime
|
||||
loadBody: MonoTime
|
||||
loadSym, loadType, loadBodies: MonoTime
|
||||
|
||||
when BenchIC:
|
||||
proc echoTimes*(m: PackedModuleGraph) =
|
||||
echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
|
||||
m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
|
||||
|
||||
template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
|
||||
template len*(m: PackedModuleGraph): int = m.pm.len
|
||||
|
||||
proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
|
||||
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
|
||||
|
||||
proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
|
||||
if c.lastLit == f and c.lastModule == thisModule:
|
||||
if f == LitId(0):
|
||||
result = InvalidFileIdx
|
||||
elif c.lastLit == f and c.lastModule == thisModule:
|
||||
result = c.lastFile
|
||||
else:
|
||||
result = toFileIndex(f, g[thisModule].fromDisk, c.config)
|
||||
@@ -748,8 +808,9 @@ proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule:
|
||||
proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
x: PackedLineInfo): TLineInfo =
|
||||
assert g[thisModule].status in {loaded, storing, stored}
|
||||
result = TLineInfo(line: x.line, col: x.col,
|
||||
fileIndex: toFileIndexCached(c, g, thisModule, x.file))
|
||||
let (fileId, line, col) = unpack(g[thisModule].fromDisk.man, x)
|
||||
result = TLineInfo(line: line.uint16, col: col.int16,
|
||||
fileIndex: toFileIndexCached(c, g, thisModule, fileId))
|
||||
|
||||
proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
tree: PackedTree; n: NodePos): PNode =
|
||||
@@ -763,14 +824,13 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
result.flags = n.flags
|
||||
|
||||
case k
|
||||
of nkEmpty, nkNilLit, nkType:
|
||||
of nkNone, nkEmpty, nkNilLit, nkType:
|
||||
discard
|
||||
of nkIdent:
|
||||
result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
|
||||
of nkSym:
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
|
||||
of directIntLit:
|
||||
result.intVal = tree.nodes[n.int].operand
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
|
||||
if result.typ == nil: result.typ = result.sym.typ
|
||||
of externIntLit:
|
||||
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -779,10 +839,11 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
|
||||
result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, n)
|
||||
assert n1.kind == nkInt32Lit
|
||||
assert n2.kind == nkInt32Lit
|
||||
assert n1.kind == nkNone
|
||||
assert n2.kind == nkNone
|
||||
transitionNoneToSym(result)
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
|
||||
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
|
||||
if result.typ == nil: result.typ = result.sym.typ
|
||||
else:
|
||||
for n0 in sonsReadonly(tree, n):
|
||||
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
|
||||
@@ -879,11 +940,25 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
result.loc.flags = s.locFlags
|
||||
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
|
||||
|
||||
proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
|
||||
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
fileIdx: FileIndex; m: var LoadedModule)
|
||||
|
||||
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
|
||||
if s == nilItemId:
|
||||
result = nil
|
||||
else:
|
||||
let si = moduleIndex(c, g, thisModule, s)
|
||||
if si >= g.len:
|
||||
g.pm.setLen(si+1)
|
||||
|
||||
if g[si].status == undefined and c.config.cmd == cmdM:
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
|
||||
for m in cachedModules:
|
||||
loadToReplayNodes(g, c.config, c.cache, m, g[int m])
|
||||
|
||||
assert g[si].status in {loaded, storing, stored}
|
||||
if not g[si].symsInit:
|
||||
g[si].symsInit = true
|
||||
@@ -898,6 +973,7 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
|
||||
else:
|
||||
result = g[si].module
|
||||
assert result != nil
|
||||
g[si].syms[s.item] = result
|
||||
|
||||
else:
|
||||
result = g[si].syms[s.item]
|
||||
@@ -942,9 +1018,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
|
||||
# store it here early on, so that recursions work properly:
|
||||
g[si].types[t.item] = result
|
||||
typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
|
||||
#assert result.itemId.item == t.item, $(result.itemId.item, t.item)
|
||||
assert result.itemId.item > 0, $(result.itemId.item, t.item)
|
||||
else:
|
||||
result = g[si].types[t.item]
|
||||
assert result.itemId.item > 0
|
||||
assert result.itemId.item > 0, "2"
|
||||
|
||||
proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
fileIdx: FileIndex; m: var LoadedModule) =
|
||||
@@ -994,30 +1072,36 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
|
||||
# Does the file belong to the fileIdx need to be recompiled?
|
||||
let m = int(fileIdx)
|
||||
if m >= g.len:
|
||||
g.setLen(m+1)
|
||||
g.pm.setLen(m+1)
|
||||
|
||||
case g[m].status
|
||||
of undefined:
|
||||
g[m].status = loading
|
||||
let fullpath = msgs.toFullPath(conf, fileIdx)
|
||||
let rod = toRodFile(conf, AbsoluteFile fullpath)
|
||||
let err = loadRodFile(rod, g[m].fromDisk, conf)
|
||||
let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
|
||||
if err == ok:
|
||||
result = optForceFullMake in conf.globalOptions
|
||||
# check its dependencies:
|
||||
for dep in g[m].fromDisk.imports:
|
||||
let fid = toFileIndex(dep, g[m].fromDisk, conf)
|
||||
# Warning: we need to traverse the full graph, so
|
||||
# do **not use break here**!
|
||||
if needsRecompile(g, conf, cache, fid, cachedModules):
|
||||
result = true
|
||||
|
||||
if not result:
|
||||
if conf.cmd == cmdM:
|
||||
setupLookupTables(g, conf, cache, fileIdx, g[m])
|
||||
cachedModules.add fileIdx
|
||||
g[m].status = loaded
|
||||
result = false
|
||||
else:
|
||||
g[m] = LoadedModule(status: outdated, module: g[m].module)
|
||||
result = optForceFullMake in conf.globalOptions
|
||||
# check its dependencies:
|
||||
for dep in g[m].fromDisk.imports:
|
||||
let fid = toFileIndex(dep, g[m].fromDisk, conf)
|
||||
# Warning: we need to traverse the full graph, so
|
||||
# do **not use break here**!
|
||||
if needsRecompile(g, conf, cache, fid, cachedModules):
|
||||
result = true
|
||||
|
||||
if not result:
|
||||
setupLookupTables(g, conf, cache, fileIdx, g[m])
|
||||
cachedModules.add fileIdx
|
||||
g[m].status = loaded
|
||||
else:
|
||||
g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
|
||||
else:
|
||||
loadError(err, rod, conf)
|
||||
g[m].status = outdated
|
||||
@@ -1032,12 +1116,13 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
|
||||
proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
|
||||
## Returns 'nil' if the module needs to be recompiled.
|
||||
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
|
||||
result = nil
|
||||
else:
|
||||
result = g[int fileIdx].module
|
||||
assert result != nil
|
||||
assert result.position == int(fileIdx)
|
||||
bench g.depAnalysis:
|
||||
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
|
||||
result = nil
|
||||
else:
|
||||
result = g[int fileIdx].module
|
||||
assert result != nil
|
||||
assert result.position == int(fileIdx)
|
||||
for m in cachedModules:
|
||||
loadToReplayNodes(g, conf, cache, m, g[int m])
|
||||
|
||||
@@ -1051,46 +1136,49 @@ template setupDecoder() {.dirty.} =
|
||||
|
||||
proc loadProcBody*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; s: PSym): PNode =
|
||||
let mId = s.itemId.module
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
|
||||
assert pos != emptyNodeId
|
||||
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
|
||||
bench g.loadBody:
|
||||
let mId = s.itemId.module
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
|
||||
assert pos != emptyNodeId
|
||||
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
|
||||
|
||||
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
|
||||
if id.item < g[module].types.len:
|
||||
result = g[module].types[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
result = loadType(decoder, g, module, id)
|
||||
bench g.loadType:
|
||||
if id.item < g[module].types.len:
|
||||
result = g[module].types[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
result = loadType(decoder, g, module, id)
|
||||
|
||||
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
|
||||
if id.item < g[module].syms.len:
|
||||
result = g[module].syms[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
result = loadSym(decoder, g, module, id)
|
||||
bench g.loadSym:
|
||||
if id.item < g[module].syms.len:
|
||||
result = g[module].syms[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
lastFile: FileIndex(-1),
|
||||
config: config,
|
||||
cache: cache)
|
||||
result = loadSym(decoder, g, module, id)
|
||||
|
||||
proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
|
||||
if id.module == LitId(0):
|
||||
@@ -1154,7 +1242,7 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
result = nil
|
||||
|
||||
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
|
||||
g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
|
||||
it.decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
lastLit: LitId(0),
|
||||
@@ -1215,7 +1303,7 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
|
||||
if err != ok:
|
||||
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
|
||||
|
||||
when true:
|
||||
when false:
|
||||
echo "exports:"
|
||||
for ex in m.exports:
|
||||
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
|
||||
@@ -1231,13 +1319,32 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
|
||||
for ex in m.hidden:
|
||||
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
|
||||
|
||||
echo "all symbols"
|
||||
for i in 0..high(m.syms):
|
||||
if m.syms[i].name != LitId(0):
|
||||
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
|
||||
else:
|
||||
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
|
||||
when false:
|
||||
echo "all symbols"
|
||||
for i in 0..high(m.syms):
|
||||
if m.syms[i].name != LitId(0):
|
||||
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
|
||||
else:
|
||||
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
|
||||
|
||||
echo "symbols: ", m.syms.len, " types: ", m.types.len,
|
||||
" top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len,
|
||||
" top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
|
||||
" strings: ", m.strings.len, " numbers: ", m.numbers.len
|
||||
|
||||
echo "SIZES:"
|
||||
echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
|
||||
" top level nodes: ", m.topLevel.len * sizeof(PackedNode),
|
||||
" other nodes: ", m.bodies.len * sizeof(PackedNode),
|
||||
" strings: ", sizeOnDisc(m.strings)
|
||||
when false:
|
||||
var tt = 0
|
||||
var fc = 0
|
||||
for x in m.topLevel:
|
||||
if x.kind == nkSym or x.typeId == nilItemId: inc tt
|
||||
if x.flags == {}: inc fc
|
||||
for x in m.bodies:
|
||||
if x.kind == nkSym or x.typeId == nilItemId: inc tt
|
||||
if x.flags == {}: inc fc
|
||||
let total = float(m.topLevel.len + m.bodies.len)
|
||||
echo "nodes with nil type: ", tt, " in % ", tt.float / total
|
||||
echo "nodes with empty flags: ", fc.float / total
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Integrity checking for a set of .rod files.
|
||||
## The set must cover a complete Nim project.
|
||||
|
||||
import sets
|
||||
import std/sets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -72,15 +72,16 @@ proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
|
||||
c.thisModule = oldThisModule
|
||||
|
||||
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
|
||||
if tree[n.int].typeId != nilItemId:
|
||||
checkType(c, tree[n.int].typeId)
|
||||
let t = findType(tree, n)
|
||||
if t != nilItemId:
|
||||
checkType(c, t)
|
||||
case n.kind
|
||||
of nkEmpty, nkNilLit, nkType, nkNilRodNode:
|
||||
discard
|
||||
of nkIdent:
|
||||
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
|
||||
of nkSym:
|
||||
checkLocalSym(c, tree.nodes[n.int].operand)
|
||||
checkLocalSym(c, tree[n].soperand)
|
||||
of directIntLit:
|
||||
discard
|
||||
of externIntLit, nkFloatLit..nkFloat128Lit:
|
||||
@@ -89,9 +90,9 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
|
||||
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, n)
|
||||
assert n1.kind == nkInt32Lit
|
||||
assert n2.kind == nkInt32Lit
|
||||
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
|
||||
assert n1.kind == nkNone
|
||||
assert n2.kind == nkNone
|
||||
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
|
||||
else:
|
||||
for n0 in sonsReadonly(tree, n):
|
||||
checkNode(c, tree, n0)
|
||||
@@ -134,13 +135,15 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
|
||||
typeInstCache*: seq[(PackedItemId, PackedItemId)]
|
||||
procInstCache*: seq[PackedInstantiation]
|
||||
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
|
||||
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
|
||||
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
|
||||
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
|
||||
methodsPerType*: seq[(PackedItemId, PackedItemId)]
|
||||
dispatchers*: seq[PackedItemId]
|
||||
]#
|
||||
|
||||
proc checkIntegrity*(g: ModuleGraph) =
|
||||
var c = CheckedContext(g: g)
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
@@ -150,4 +153,3 @@ proc checkIntegrity*(g: ModuleGraph) =
|
||||
of stored, storing, outdated, loaded:
|
||||
c.thisModule = int32 i
|
||||
checkModule(c, g.packed[i].fromDisk)
|
||||
|
||||
|
||||
@@ -11,29 +11,34 @@
|
||||
## IDE-like features. It uses the set of .rod files to accomplish
|
||||
## its task. The set must cover a complete Nim project.
|
||||
|
||||
import sets
|
||||
import std/sets
|
||||
|
||||
from os import nil
|
||||
from std/os import nil
|
||||
from std/private/miscdollars import toLocation
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import ".." / [ast, modulegraphs, msgs, options]
|
||||
import ".." / nir / nirlineinfos
|
||||
import packed_ast, bitabs, ic
|
||||
|
||||
type
|
||||
UnpackedLineInfo = object
|
||||
file: LitId
|
||||
line, col: int
|
||||
NavContext = object
|
||||
g: ModuleGraph
|
||||
thisModule: int32
|
||||
trackPos: PackedLineInfo
|
||||
trackPos: UnpackedLineInfo
|
||||
alreadyEmitted: HashSet[string]
|
||||
outputSep: char # for easier testing, use short filenames and spaces instead of tabs.
|
||||
|
||||
proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
|
||||
if current.file == trackPos.file and current.line == trackPos.line:
|
||||
proc isTracked(man: LineInfoManager; current: PackedLineInfo, trackPos: UnpackedLineInfo, tokenLen: int): bool =
|
||||
let (currentFile, currentLine, currentCol) = man.unpack(current)
|
||||
if currentFile == trackPos.file and currentLine == trackPos.line:
|
||||
let col = trackPos.col
|
||||
if col >= current.col and col < current.col+tokenLen:
|
||||
if col >= currentCol and col < currentCol+tokenLen:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
@@ -42,32 +47,34 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
|
||||
|
||||
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
|
||||
result = s.name != LitId(0) and
|
||||
isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
|
||||
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
|
||||
|
||||
proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool =
|
||||
let name = c.g.packed[s.module].fromDisk.syms[s.item].name
|
||||
result = name != LitId(0) and
|
||||
isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
|
||||
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
|
||||
|
||||
const
|
||||
EmptyItemId = ItemId(module: -1'i32, item: -1'i32)
|
||||
|
||||
proc search(c: var NavContext; tree: PackedTree): ItemId =
|
||||
# We use the linear representation here directly:
|
||||
for i in 0..high(tree.nodes):
|
||||
case tree.nodes[i].kind
|
||||
for i in 0..<len(tree):
|
||||
let i = NodePos(i)
|
||||
case tree[i].kind
|
||||
of nkSym:
|
||||
let item = tree.nodes[i].operand
|
||||
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info):
|
||||
let item = tree[i].soperand
|
||||
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree[i].info):
|
||||
return ItemId(module: c.thisModule, item: item)
|
||||
of nkModuleRef:
|
||||
if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file:
|
||||
let (n1, n2) = sons2(tree, NodePos i)
|
||||
let (currentFile, currentLine, currentCol) = c.g.packed[c.thisModule].fromDisk.man.unpack(tree[i].info)
|
||||
if currentLine == c.trackPos.line and currentFile == c.trackPos.file:
|
||||
let (n1, n2) = sons2(tree, i)
|
||||
assert n1.kind == nkInt32Lit
|
||||
assert n2.kind == nkInt32Lit
|
||||
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
|
||||
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
|
||||
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
|
||||
if searchForeignSym(c, itemId, tree.nodes[i].info):
|
||||
if searchForeignSym(c, itemId, tree[i].info):
|
||||
return itemId
|
||||
else: discard
|
||||
return EmptyItemId
|
||||
@@ -77,36 +84,38 @@ proc isDecl(tree: PackedTree; n: NodePos): bool =
|
||||
const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef,
|
||||
nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection,
|
||||
nkIdentDefs, nkEnumTy, nkVarTuple}
|
||||
result = n.int >= 0 and tree[n.int].kind in declarativeNodes
|
||||
result = n.int >= 0 and tree[n].kind in declarativeNodes
|
||||
|
||||
proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) =
|
||||
let (fileId, line, col) = unpack(c.g.packed[c.thisModule].fromDisk.man, info)
|
||||
var m = ""
|
||||
var file = c.g.packed[c.thisModule].fromDisk.strings[info.file]
|
||||
var file = c.g.packed[c.thisModule].fromDisk.strings[fileId]
|
||||
if c.outputSep == ' ':
|
||||
file = os.extractFilename file
|
||||
toLocation(m, file, info.line.int, info.col.int + ColOffset)
|
||||
toLocation(m, file, line, col + ColOffset)
|
||||
if not c.alreadyEmitted.containsOrIncl(m):
|
||||
msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m
|
||||
|
||||
proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
|
||||
for i in 0..high(tree.nodes):
|
||||
case tree.nodes[i].kind
|
||||
for i in 0..<len(tree):
|
||||
let i = NodePos(i)
|
||||
case tree[i].kind
|
||||
of nkSym:
|
||||
let item = tree.nodes[i].operand
|
||||
let item = tree[i].soperand
|
||||
if sym.item == item and sym.module == c.thisModule:
|
||||
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
|
||||
usage(c, tree[i].info, isDecl(tree, parent(i)))
|
||||
of nkModuleRef:
|
||||
let (n1, n2) = sons2(tree, NodePos i)
|
||||
assert n1.kind == nkInt32Lit
|
||||
assert n2.kind == nkInt32Lit
|
||||
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
|
||||
let (n1, n2) = sons2(tree, i)
|
||||
assert n1.kind == nkNone
|
||||
assert n2.kind == nkNone
|
||||
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
|
||||
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
|
||||
if itemId.item == sym.item and sym.module == itemId.module:
|
||||
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
|
||||
usage(c, tree[i].info, isDecl(tree, parent(i)))
|
||||
else: discard
|
||||
|
||||
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
for k in 1..high(g.packed[i].fromDisk.includes):
|
||||
# we start from 1 because the first "include" file is
|
||||
# the module's filename.
|
||||
@@ -138,7 +147,7 @@ proc nav(g: ModuleGraph) =
|
||||
var c = NavContext(
|
||||
g: g,
|
||||
thisModule: int32 mid,
|
||||
trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId),
|
||||
trackPos: UnpackedLineInfo(line: unpacked.line.int, col: unpacked.col.int, file: fileId),
|
||||
outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t'
|
||||
)
|
||||
var symId = search(c, g.packed[mid].fromDisk.topLevel)
|
||||
@@ -149,7 +158,7 @@ proc nav(g: ModuleGraph) =
|
||||
localError(g.config, unpacked, "no symbol at this position")
|
||||
return
|
||||
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
# case statement here to enforce exhaustive checks.
|
||||
case g.packed[i].status
|
||||
of undefined:
|
||||
@@ -166,7 +175,7 @@ proc navUsages*(g: ModuleGraph) = nav(g)
|
||||
proc navDefusages*(g: ModuleGraph) = nav(g)
|
||||
|
||||
proc writeRodFiles*(g: ModuleGraph) =
|
||||
for i in 0..high(g.packed):
|
||||
for i in 0..<len(g.packed):
|
||||
case g.packed[i].status
|
||||
of undefined, loading, stored, loaded:
|
||||
discard "nothing to do"
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
## use this representation directly in all the transformations,
|
||||
## it is superior.
|
||||
|
||||
import hashes, tables, strtabs
|
||||
import bitabs
|
||||
import std/[hashes, tables, strtabs]
|
||||
import bitabs, rodfiles
|
||||
import ".." / [ast, options]
|
||||
|
||||
import ".." / nir / nirlineinfos
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -31,17 +33,12 @@ type
|
||||
item*: int32 # same as the in-memory representation
|
||||
|
||||
const
|
||||
nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
|
||||
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
|
||||
|
||||
const
|
||||
emptyNodeId* = NodeId(-1)
|
||||
|
||||
type
|
||||
PackedLineInfo* = object
|
||||
line*: uint16
|
||||
col*: int16
|
||||
file*: LitId
|
||||
|
||||
PackedLib* = object
|
||||
kind*: TLibKind
|
||||
generated*: bool
|
||||
@@ -90,23 +87,35 @@ type
|
||||
typeInst*: PackedItemId
|
||||
nonUniqueId*: int32
|
||||
|
||||
PackedNode* = object # 28 bytes
|
||||
kind*: TNodeKind
|
||||
flags*: TNodeFlags
|
||||
operand*: int32 # for kind in {nkSym, nkSymDef}: SymId
|
||||
# for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
|
||||
# for kind in nkInt32Lit: direct value
|
||||
# for non-atom kinds: the number of nodes (for easy skipping)
|
||||
typeId*: PackedItemId
|
||||
PackedNode* = object # 8 bytes
|
||||
x: uint32
|
||||
info*: PackedLineInfo
|
||||
|
||||
PackedTree* = object ## usually represents a full Nim module
|
||||
nodes*: seq[PackedNode]
|
||||
nodes: seq[PackedNode]
|
||||
withFlags: seq[(int32, TNodeFlags)]
|
||||
withTypes: seq[(int32, PackedItemId)]
|
||||
|
||||
PackedInstantiation* = object
|
||||
key*, sym*: PackedItemId
|
||||
concreteTypes*: seq[PackedItemId]
|
||||
|
||||
const
|
||||
NodeKindBits = 8'u32
|
||||
NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
|
||||
|
||||
template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
|
||||
template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
|
||||
template soperand*(n: PackedNode): int32 = int32(uoperand(n))
|
||||
|
||||
template toX(k: TNodeKind; operand: uint32): uint32 =
|
||||
uint32(k) or (operand shl NodeKindBits)
|
||||
|
||||
template toX(k: TNodeKind; operand: LitId): uint32 =
|
||||
uint32(k) or (operand.uint32 shl NodeKindBits)
|
||||
|
||||
template typeId*(n: PackedNode): PackedItemId = n.typ
|
||||
|
||||
proc `==`*(a, b: SymId): bool {.borrow.}
|
||||
proc hash*(a: SymId): Hash {.borrow.}
|
||||
|
||||
@@ -118,68 +127,32 @@ proc newTreeFrom*(old: PackedTree): PackedTree =
|
||||
result.nodes = @[]
|
||||
when false: result.sh = old.sh
|
||||
|
||||
when false:
|
||||
proc declareSym*(tree: var PackedTree; kind: TSymKind;
|
||||
name: LitId; info: PackedLineInfo): SymId =
|
||||
result = SymId(tree.sh.syms.len)
|
||||
tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info)
|
||||
|
||||
proc litIdFromName*(tree: PackedTree; name: string): LitId =
|
||||
result = tree.sh.strings.getOrIncl(name)
|
||||
|
||||
proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: kind, info: info,
|
||||
operand: int32 getOrIncl(tree.sh.strings, token))
|
||||
|
||||
proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
|
||||
|
||||
proc throwAwayLastNode*(tree: var PackedTree) =
|
||||
tree.nodes.setLen(tree.nodes.len-1)
|
||||
|
||||
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info)
|
||||
tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
|
||||
|
||||
proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info)
|
||||
|
||||
proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info)
|
||||
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
|
||||
|
||||
proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
|
||||
tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info)
|
||||
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
|
||||
|
||||
proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
|
||||
|
||||
proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) =
|
||||
# and this is why the IR is superior. We can copy subtrees
|
||||
# via a linear scan.
|
||||
let pos = n.int
|
||||
let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
|
||||
let d = dest.nodes.len
|
||||
dest.nodes.setLen(d + L)
|
||||
for i in 0..<L:
|
||||
dest.nodes[d+i] = tree.nodes[pos+i]
|
||||
|
||||
when false:
|
||||
proc copySym*(dest: var PackedTree; tree: PackedTree; s: SymId): SymId =
|
||||
result = SymId(dest.sh.syms.len)
|
||||
assert int(s) < tree.sh.syms.len
|
||||
let oldSym = tree.sh.syms[s.int]
|
||||
dest.sh.syms.add oldSym
|
||||
|
||||
type
|
||||
PatchPos = distinct int
|
||||
|
||||
when false:
|
||||
proc prepare*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo): PatchPos =
|
||||
result = PatchPos tree.nodes.len
|
||||
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
|
||||
proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
|
||||
typeId: PackedItemId = nilItemId; info: PackedLineInfo;
|
||||
flags: TNodeFlags = {}) =
|
||||
t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
|
||||
if flags != {}:
|
||||
t.withFlags.add (t.nodes.len.int32 - 1, flags)
|
||||
if typeId != nilItemId:
|
||||
t.withTypes.add (t.nodes.len.int32 - 1, typeId)
|
||||
|
||||
proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
|
||||
result = PatchPos tree.nodes.len
|
||||
tree.nodes.add PackedNode(kind: kind, flags: flags, operand: 0, info: info,
|
||||
typeId: typeId)
|
||||
tree.addNode(kind = kind, flags = flags, operand = 0, info = info, typeId = typeId)
|
||||
|
||||
proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
|
||||
result = PatchPos dest.nodes.len
|
||||
@@ -187,26 +160,30 @@ proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): Pat
|
||||
|
||||
proc patch*(tree: var PackedTree; pos: PatchPos) =
|
||||
let pos = pos.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let k = tree.nodes[pos].kind
|
||||
assert k > nkNilLit
|
||||
let distance = int32(tree.nodes.len - pos)
|
||||
tree.nodes[pos].operand = distance
|
||||
assert distance > 0
|
||||
tree.nodes[pos].x = toX(k, cast[uint32](distance))
|
||||
|
||||
proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
|
||||
|
||||
proc `[]`*(tree: PackedTree; i: int): lent PackedNode {.inline.} =
|
||||
tree.nodes[i]
|
||||
proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
|
||||
tree.nodes[i.int]
|
||||
|
||||
template rawSpan(n: PackedNode): int = int(uoperand(n))
|
||||
|
||||
proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
|
||||
if tree.nodes[pos].kind > nkNilLit:
|
||||
assert tree.nodes[pos].operand > 0
|
||||
inc pos, tree.nodes[pos].operand
|
||||
assert tree.nodes[pos].uoperand > 0
|
||||
inc pos, tree.nodes[pos].rawSpan
|
||||
else:
|
||||
inc pos
|
||||
|
||||
iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let last = pos + tree.nodes[pos].operand
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
@@ -227,7 +204,7 @@ iterator isons*(dest: var PackedTree; tree: PackedTree;
|
||||
iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let last = pos + tree.nodes[pos].operand
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
if pos < last:
|
||||
nextChild tree, pos
|
||||
@@ -241,7 +218,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
|
||||
inc count
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > nkNilLit
|
||||
let last = pos + tree.nodes[pos].operand
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
while pos < last and count > 2:
|
||||
yield NodePos pos
|
||||
@@ -251,7 +228,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
|
||||
proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
|
||||
# finding the parent of a node is rather easy:
|
||||
var pos = n.int - 1
|
||||
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)):
|
||||
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
|
||||
dec pos
|
||||
#assert pos >= 0, "node has no parent"
|
||||
result = NodePos(pos)
|
||||
@@ -277,20 +254,32 @@ proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
|
||||
proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
|
||||
tree.nodes[n.int].kind
|
||||
proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
|
||||
LitId tree.nodes[n.int].operand
|
||||
LitId tree.nodes[n.int].uoperand
|
||||
proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
|
||||
tree.nodes[n.int].info
|
||||
|
||||
template typ*(n: NodePos): PackedItemId =
|
||||
tree.nodes[n.int].typeId
|
||||
template flags*(n: NodePos): TNodeFlags =
|
||||
tree.nodes[n.int].flags
|
||||
proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
|
||||
for x in tree.withTypes:
|
||||
if x[0] == int32(n): return x[1]
|
||||
if x[0] > int32(n): return nilItemId
|
||||
return nilItemId
|
||||
|
||||
template operand*(n: NodePos): int32 =
|
||||
tree.nodes[n.int].operand
|
||||
proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
|
||||
for x in tree.withFlags:
|
||||
if x[0] == int32(n): return x[1]
|
||||
if x[0] > int32(n): return {}
|
||||
return {}
|
||||
|
||||
template typ*(n: NodePos): PackedItemId =
|
||||
tree.findType(n)
|
||||
template flags*(n: NodePos): TNodeFlags =
|
||||
tree.findFlags(n)
|
||||
|
||||
template uoperand*(n: NodePos): uint32 =
|
||||
tree.nodes[n.int].uoperand
|
||||
|
||||
proc span*(tree: PackedTree; pos: int): int {.inline.} =
|
||||
if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
|
||||
if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
|
||||
|
||||
proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
|
||||
assert(not isAtom(tree, n.int))
|
||||
@@ -320,64 +309,28 @@ when false:
|
||||
|
||||
template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
|
||||
template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
|
||||
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand
|
||||
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
|
||||
|
||||
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
|
||||
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
|
||||
|
||||
proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
|
||||
|
||||
when false:
|
||||
# xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
|
||||
proc strLit*(tree: PackedTree; n: NodePos): lent string =
|
||||
assert n.kind == nkStrLit
|
||||
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
|
||||
|
||||
proc strVal*(tree: PackedTree; n: NodePos): string =
|
||||
assert n.kind == nkStrLit
|
||||
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
|
||||
#result = cookedStrLit(raw)
|
||||
|
||||
proc filenameVal*(tree: PackedTree; n: NodePos): string =
|
||||
case n.kind
|
||||
of nkStrLit:
|
||||
result = strVal(tree, n)
|
||||
of nkIdent:
|
||||
result = tree.sh.strings[n.litId]
|
||||
of nkSym:
|
||||
result = tree.sh.strings[tree.sh.syms[int n.symId].name]
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc identAsStr*(tree: PackedTree; n: NodePos): lent string =
|
||||
assert n.kind == nkIdent
|
||||
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
|
||||
|
||||
const
|
||||
externIntLit* = {nkCharLit,
|
||||
nkIntLit,
|
||||
nkInt8Lit,
|
||||
nkInt16Lit,
|
||||
nkInt32Lit,
|
||||
nkInt64Lit,
|
||||
nkUIntLit,
|
||||
nkUInt8Lit,
|
||||
nkUInt16Lit,
|
||||
nkUInt32Lit,
|
||||
nkUInt64Lit} # nkInt32Lit is missing by design!
|
||||
nkUInt64Lit}
|
||||
|
||||
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit}
|
||||
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
|
||||
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
|
||||
directIntLit* = nkInt32Lit
|
||||
|
||||
when false:
|
||||
proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
|
||||
if n.kind == nkIdent:
|
||||
result = n.litId
|
||||
elif n.kind == nkSym:
|
||||
result = tree.sh.syms[int n.symId].name
|
||||
else:
|
||||
result = LitId(0)
|
||||
|
||||
template identId*(n: NodePos): LitId = identIdImpl(tree, n)
|
||||
directIntLit* = nkNone
|
||||
|
||||
template copyInto*(dest, n, body) =
|
||||
let patchPos = prepare(dest, tree, n)
|
||||
@@ -389,28 +342,8 @@ template copyIntoKind*(dest, kind, info, body) =
|
||||
body
|
||||
patch dest, patchPos
|
||||
|
||||
when false:
|
||||
proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool =
|
||||
let litId = tree.sh.strings.getKeyId(pragma)
|
||||
if litId == LitId(0):
|
||||
return false
|
||||
assert n.kind == nkPragma
|
||||
for ch0 in sonsReadonly(tree, n):
|
||||
if ch0.kind == nkExprColonExpr:
|
||||
if ch0.firstSon.identId == litId:
|
||||
return true
|
||||
elif ch0.identId == litId:
|
||||
return true
|
||||
|
||||
proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
|
||||
|
||||
when false:
|
||||
proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) =
|
||||
let patchPos = prepare(dest, nkError, n.info)
|
||||
dest.add nkStrLit, msg, n.info
|
||||
copyTree(dest, tree, n)
|
||||
patch dest, patchPos
|
||||
|
||||
iterator allNodes*(tree: PackedTree): NodePos =
|
||||
var p = 0
|
||||
while p < tree.len:
|
||||
@@ -420,3 +353,13 @@ iterator allNodes*(tree: PackedTree): NodePos =
|
||||
|
||||
proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
|
||||
PackedItemId(module: LitId(0), item: item)
|
||||
|
||||
proc load*(f: var RodFile; t: var PackedTree) =
|
||||
loadSeq f, t.nodes
|
||||
loadSeq f, t.withFlags
|
||||
loadSeq f, t.withTypes
|
||||
|
||||
proc store*(f: var RodFile; t: PackedTree) =
|
||||
storeSeq f, t.nodes
|
||||
storeSeq f, t.withFlags
|
||||
storeSeq f, t.withTypes
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import ".." / [ast, modulegraphs, trees, extccomp, btrees,
|
||||
msgs, lineinfos, pathutils, options, cgmeth]
|
||||
|
||||
import tables
|
||||
import std/tables
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -103,6 +103,17 @@ proc replayBackendProcs*(g: ModuleGraph; module: int) =
|
||||
let symId = FullId(module: tmp.module, packed: it[1])
|
||||
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.methodsPerType):
|
||||
let key = translateId(it[0], g.packed, module, g.config)
|
||||
let tmp = translateId(it[1], g.packed, module, g.config)
|
||||
let symId = FullId(module: tmp.module, packed: it[1])
|
||||
g.methodsPerType.mgetOrPut(key, @[]).add LazySym(id: symId, sym: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.dispatchers):
|
||||
let tmp = translateId(it, g.packed, module, g.config)
|
||||
let symId = FullId(module: tmp.module, packed: it)
|
||||
g.dispatchers.add LazySym(id: symId, sym: nil)
|
||||
|
||||
proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
|
||||
## We remember the generic instantiations a module performed
|
||||
## in order to to avoid the code bloat that generic code tends
|
||||
@@ -127,12 +138,12 @@ proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
|
||||
module: module, sym: FullId(module: sym.module, packed: it.sym),
|
||||
concreteTypes: concreteTypes, inst: nil)
|
||||
|
||||
for it in mitems(g.packed[module].fromDisk.methodsPerType):
|
||||
for it in mitems(g.packed[module].fromDisk.methodsPerGenericType):
|
||||
let key = translateId(it[0], g.packed, module, g.config)
|
||||
let col = it[1]
|
||||
let tmp = translateId(it[2], g.packed, module, g.config)
|
||||
let symId = FullId(module: tmp.module, packed: it[2])
|
||||
g.methodsPerType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
|
||||
g.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
|
||||
|
||||
replayBackendProcs(g, module)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
## compiler works and less a storage format, you're probably looking for
|
||||
## the `ic` or `packed_ast` modules to understand the logical format.
|
||||
|
||||
from typetraits import supportsCopyMem
|
||||
from std/typetraits import supportsCopyMem
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
@@ -92,11 +92,16 @@ type
|
||||
typeInstCacheSection
|
||||
procInstCacheSection
|
||||
attachedOpsSection
|
||||
methodsPerTypeSection
|
||||
methodsPerGenericTypeSection
|
||||
enumToStringProcsSection
|
||||
methodsPerTypeSection
|
||||
dispatchersSection
|
||||
typeInfoSection # required by the backend
|
||||
backendFlagsSection
|
||||
aliveSymsSection # beware, this is stored in a `.alivesyms` file.
|
||||
sideChannelSection
|
||||
namespaceSection
|
||||
symnamesSection
|
||||
|
||||
RodFileError* = enum
|
||||
ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch,
|
||||
@@ -109,8 +114,8 @@ type
|
||||
# better than exceptions.
|
||||
|
||||
const
|
||||
RodVersion = 1
|
||||
cookie = [byte(0), byte('R'), byte('O'), byte('D'),
|
||||
RodVersion = 2
|
||||
defaultCookie = [byte(0), byte('R'), byte('O'), byte('D'),
|
||||
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)]
|
||||
|
||||
proc setError(f: var RodFile; err: RodFileError) {.inline.} =
|
||||
@@ -206,13 +211,13 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
|
||||
for i in 0..<lenPrefix:
|
||||
loadPrim(f, s[i])
|
||||
|
||||
proc storeHeader*(f: var RodFile) =
|
||||
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
|
||||
## stores the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
if f.f.writeBytes(cookie, 0, cookie.len) != cookie.len:
|
||||
setError f, ioFailure
|
||||
|
||||
proc loadHeader*(f: var RodFile) =
|
||||
proc loadHeader*(f: var RodFile; cookie = defaultCookie) =
|
||||
## Loads the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
# An identifier is a shared immutable string that can be compared by its
|
||||
# id. This module is essential for the compiler's performance.
|
||||
|
||||
import
|
||||
hashes, wordrecg
|
||||
import wordrecg
|
||||
import std/hashes
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
## This module implements the symbol importing mechanism.
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, modulepaths, sigmatch, lineinfos, sets,
|
||||
modulegraphs, wordrecg, tables
|
||||
from strutils import `%`
|
||||
ast, astalgo, msgs, options, idents, lookups,
|
||||
semdata, modulepaths, sigmatch, lineinfos,
|
||||
modulegraphs, wordrecg
|
||||
from std/strutils import `%`, startsWith
|
||||
from std/sequtils import addUnique
|
||||
import std/[sets, tables, intsets]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -229,11 +231,6 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
|
||||
for i in 0..n.safeLen-1:
|
||||
importForwarded(c, n[i], exceptSet, fromMod, importSet)
|
||||
|
||||
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
|
||||
for i in 0..high(x):
|
||||
if x[i] == y: return
|
||||
x.add y
|
||||
|
||||
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
|
||||
result = realModule
|
||||
template createModuleAliasImpl(ident): untyped =
|
||||
@@ -305,6 +302,10 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
|
||||
var prefix = ""
|
||||
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
|
||||
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
|
||||
let moduleName = getModuleName(c.config, n)
|
||||
if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and
|
||||
not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"):
|
||||
message(c.config, n.info, warnStdPrefix, realModule.name.s)
|
||||
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
|
||||
importStmtResult.add newSymNode(result, n.info)
|
||||
#newStrNode(toFullPath(c.config, f), n.info)
|
||||
@@ -312,6 +313,7 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
|
||||
result = nil
|
||||
|
||||
proc afterImport(c: PContext, m: PSym) =
|
||||
if isCachedModule(c.graph, m): return
|
||||
# fixes bug #17510, for re-exported symbols
|
||||
let realModuleId = c.importModuleMap[m.id]
|
||||
for s in allSyms(c.graph, m):
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
## See doc/destructors.rst for a spec of the implemented rewrite rules
|
||||
|
||||
import
|
||||
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, lowerings, tables, modulegraphs,
|
||||
ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
options, lowerings, modulegraphs,
|
||||
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
|
||||
varpartitions, aliasanalysis, dfa, wordrecg
|
||||
|
||||
import std/[strtabs, tables, strutils, intsets]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -212,7 +214,7 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr
|
||||
localError(c.graph.config, ri.info, errGenerated, m)
|
||||
|
||||
proc makePtrType(c: var Con, baseType: PType): PType =
|
||||
result = newType(tyPtr, nextTypeId c.idgen, c.owner)
|
||||
result = newType(tyPtr, c.idgen, c.owner)
|
||||
addSonSkipIntLit(result, baseType, c.idgen)
|
||||
|
||||
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
|
||||
@@ -855,7 +857,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result[i][1] = p(n[i][1], c, s, m)
|
||||
else:
|
||||
result[i] = p(n[i], c, s, m)
|
||||
if mode == normal and isRefConstr:
|
||||
if mode == normal and (isRefConstr or (hasDestructor(c, t) and
|
||||
getAttachedOp(c.graph, t, attachedDestructor) != nil and
|
||||
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags)):
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
|
||||
|
||||
@@ -71,6 +71,7 @@ Files: "testament"
|
||||
Files: "nimsuggest"
|
||||
Files: "nimsuggest/tests/*.nim"
|
||||
Files: "changelogs/*.md"
|
||||
Files: "ci/funs.sh"
|
||||
|
||||
[Lib]
|
||||
Files: "lib"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This
|
||||
## type is for that purpose.
|
||||
|
||||
from math import trunc
|
||||
from std/math import trunc
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -358,7 +358,7 @@ proc `*`*(lhs, rhs: Int128): Int128 =
|
||||
proc `*=`*(a: var Int128, b: Int128) =
|
||||
a = a * b
|
||||
|
||||
import bitops
|
||||
import std/bitops
|
||||
|
||||
proc fastLog2*(a: Int128): int =
|
||||
result = 0
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
## https://github.com/nim-lang/RFCs/issues/244 for more details.
|
||||
|
||||
import
|
||||
ast, types, renderer, intsets
|
||||
ast, types, renderer
|
||||
|
||||
import std/intsets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -37,8 +37,8 @@ import
|
||||
|
||||
import pipelineutils
|
||||
|
||||
import json, sets, math, tables, intsets
|
||||
import strutils except addf
|
||||
import std/[json, sets, math, tables, intsets]
|
||||
import std/strutils except addf
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, syncio]
|
||||
@@ -2718,7 +2718,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
|
||||
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
|
||||
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, {})
|
||||
if sfInjectDestructors in prc.flags:
|
||||
transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)
|
||||
|
||||
@@ -3097,9 +3097,8 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
|
||||
var p = newInitProc(globals, m)
|
||||
attachProc(p, prc)
|
||||
|
||||
var disp = generateMethodDispatchers(graph, m.idgen)
|
||||
for i in 0..<disp.len:
|
||||
let prc = disp[i].sym
|
||||
generateIfMethodDispatchers(graph, m.idgen)
|
||||
for prc in getDispatchers(graph):
|
||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||
var p = newInitProc(globals, m)
|
||||
attachProc(p, prc)
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
# This file implements lambda lifting for the transformator.
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, msgs,
|
||||
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
|
||||
options, ast, astalgo, msgs,
|
||||
idents, renderer, types, magicsys, lowerings, modulegraphs, lineinfos,
|
||||
transf, liftdestructors, typeallowed
|
||||
|
||||
import std/[strutils, tables, intsets]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -133,10 +135,10 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
|
||||
var n = newNodeI(nkRange, iter.info)
|
||||
n.add newIntNode(nkIntLit, -1)
|
||||
n.add newIntNode(nkIntLit, 0)
|
||||
result = newType(tyRange, nextTypeId(idgen), iter)
|
||||
result = newType(tyRange, idgen, iter)
|
||||
result.n = n
|
||||
var intType = nilOrSysInt(g)
|
||||
if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter)
|
||||
if intType.isNil: intType = newType(tyInt, idgen, iter)
|
||||
rawAddSon(result, intType)
|
||||
|
||||
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
|
||||
@@ -340,7 +342,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
||||
info: TLineInfo): PType =
|
||||
result = c.ownerToType.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
result = newType(tyRef, nextTypeId(c.idgen), owner)
|
||||
result = newType(tyRef, c.idgen, owner)
|
||||
let obj = createEnvObj(c.graph, c.idgen, owner, info)
|
||||
rawAddSon(result, obj)
|
||||
c.ownerToType[owner.id] = result
|
||||
@@ -348,7 +350,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
||||
proc asOwnedRef(c: var DetectionPass; t: PType): PType =
|
||||
if optOwnedRefs in c.graph.config.globalOptions:
|
||||
assert t.kind == tyRef
|
||||
result = newType(tyOwned, nextTypeId(c.idgen), t.owner)
|
||||
result = newType(tyOwned, c.idgen, t.owner)
|
||||
result.flags.incl tfHasOwned
|
||||
result.rawAddSon t
|
||||
else:
|
||||
@@ -357,7 +359,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
|
||||
proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
|
||||
info: TLineInfo): PType =
|
||||
var r = c.getEnvTypeForOwner(owner, info)
|
||||
result = newType(tyPtr, nextTypeId(c.idgen), owner)
|
||||
result = newType(tyPtr, c.idgen, owner)
|
||||
rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr}))
|
||||
|
||||
proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
@@ -449,7 +451,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if innerProc:
|
||||
if s.isIterator: c.somethingToDo = true
|
||||
if not c.processed.containsOrIncl(s.id):
|
||||
let body = transformBody(c.graph, c.idgen, s, useCache)
|
||||
let body = transformBody(c.graph, c.idgen, s, {useCache})
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
|
||||
@@ -755,7 +757,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
|
||||
var body = transformBody(d.graph, d.idgen, s, {})
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envVars.getOrDefault(s.id).isNil:
|
||||
s.transformedBody = body
|
||||
@@ -879,7 +881,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
idgen: IdGenerator, force: bool): PNode =
|
||||
idgen: IdGenerator; flags: TransformFlags): PNode =
|
||||
# XXX backend == backendJs does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
@@ -888,7 +890,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
g.config.backend == backendJs and not isCompileTime) or
|
||||
(fn.skipGenericOwner.kind != skModule and not force):
|
||||
(fn.skipGenericOwner.kind != skModule and force notin flags):
|
||||
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
# DOS or Macintosh text files, even when it is not the native format.
|
||||
|
||||
import
|
||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
||||
wordrecg, lineinfos, pathutils, parseutils
|
||||
options, msgs, platform, idents, nimlexbase, llstream,
|
||||
wordrecg, lineinfos, pathutils
|
||||
|
||||
import std/[hashes, parseutils, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, formatfloat]
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
|
||||
|
||||
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
|
||||
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
|
||||
sighashes, lowerings, options, types, msgs, magicsys, ccgutils
|
||||
|
||||
import std/tables
|
||||
from trees import isCaseObj
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -1056,7 +1057,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
|
||||
res.typ = typ
|
||||
src.typ = typ
|
||||
|
||||
result.typ = newType(tyProc, nextTypeId idgen, owner)
|
||||
result.typ = newType(tyProc, idgen, owner)
|
||||
result.typ.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result.typ, res.typ)
|
||||
result.typ.n.add newNodeI(nkEffectList, info)
|
||||
@@ -1081,7 +1082,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
|
||||
incl result.flags, sfGeneratedOp
|
||||
|
||||
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
|
||||
if kind == attachedDup:
|
||||
return symDupPrototype(g, typ, owner, kind, info, idgen)
|
||||
|
||||
@@ -1091,7 +1092,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
|
||||
idgen, result, info)
|
||||
|
||||
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
|
||||
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}):
|
||||
dest.typ = typ
|
||||
else:
|
||||
dest.typ = makeVarType(typ.owner, typ, idgen)
|
||||
@@ -1101,7 +1103,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
else:
|
||||
src.typ = typ
|
||||
|
||||
result.typ = newProcType(info, nextTypeId(idgen), owner)
|
||||
result.typ = newProcType(info, idgen, owner)
|
||||
result.typ.addParam dest
|
||||
if kind notin {attachedDestructor, attachedWasMoved}:
|
||||
result.typ.addParam src
|
||||
@@ -1184,7 +1186,8 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
|
||||
info: TLineInfo; idgen: IdGenerator): PSym =
|
||||
assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
|
||||
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen)
|
||||
# discrimantor assignments needs pointers to destroy fields; alas, we cannot use non-var destructor here
|
||||
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen, isDiscriminant = true)
|
||||
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen,
|
||||
fn: result)
|
||||
a.asgnForType = typ
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
## This module implements the '.liftLocals' pragma.
|
||||
|
||||
import
|
||||
strutils, options, ast, msgs,
|
||||
options, ast, msgs,
|
||||
idents, renderer, types, lowerings, lineinfos
|
||||
|
||||
import std/strutils
|
||||
|
||||
from pragmas import getPragmaVal
|
||||
from wordrecg import wLiftLocals
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
## This module contains the `TMsgKind` enum as well as the
|
||||
## `TLineInfo` object.
|
||||
|
||||
import ropes, tables, pathutils, hashes
|
||||
import ropes, pathutils
|
||||
import std/[hashes, tables]
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.github.io/Nim"
|
||||
@@ -91,6 +92,7 @@ type
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
warnBareExcept = "BareExcept",
|
||||
warnImplicitDefaultValue = "ImplicitDefaultValue",
|
||||
warnStdPrefix = "StdPrefix"
|
||||
warnUser = "User",
|
||||
# hints
|
||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||
@@ -104,10 +106,10 @@ type
|
||||
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
|
||||
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
|
||||
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
|
||||
hintAmbiguousEnum = "AmbiguousEnum",
|
||||
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
|
||||
hintMsgOrigin = "MsgOrigin", # since 1.3.5
|
||||
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
|
||||
hintUnknownHint = "UnknownHint"
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
@@ -185,7 +187,7 @@ const
|
||||
warnAnyEnumConv: "$1",
|
||||
warnHoleEnumConv: "$1",
|
||||
warnCstringConv: "$1",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnCastSizes: "$1", # deadcode
|
||||
warnAboveMaxSizeSet: "$1",
|
||||
@@ -194,6 +196,7 @@ const
|
||||
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
|
||||
warnBareExcept: "$1",
|
||||
warnImplicitDefaultValue: "$1",
|
||||
warnStdPrefix: "$1 needs the 'std' prefix",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
# keep in sync with `testament.isSuccess`
|
||||
@@ -225,12 +228,12 @@ const
|
||||
hintGCStats: "$1",
|
||||
hintGlobalVar: "global variable declared here",
|
||||
hintExpandMacro: "expanded macro: $1",
|
||||
hintAmbiguousEnum: "$1",
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1",
|
||||
hintExtendedContext: "$1",
|
||||
hintMsgOrigin: "$1",
|
||||
hintDeclaredLoc: "$1",
|
||||
hintUnknownHint: "unknown hint: $1"
|
||||
]
|
||||
|
||||
const
|
||||
@@ -249,7 +252,7 @@ type
|
||||
|
||||
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||
result = default(array[0..3, TNoteKinds])
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
|
||||
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix}
|
||||
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
|
||||
result[1] = result[2] - {warnProveField, warnProveIndex,
|
||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||
|
||||
@@ -19,7 +19,7 @@ when defined(nimPreviewSlimSystem):
|
||||
const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and
|
||||
not defined(windows)
|
||||
|
||||
when hasRstdin: import rdstdin
|
||||
when hasRstdin: import std/rdstdin
|
||||
|
||||
type
|
||||
TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int
|
||||
|
||||
@@ -14,8 +14,10 @@ when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
|
||||
ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, lineinfos, modulegraphs, astmsgs, wordrecg
|
||||
|
||||
import std/[intsets, sets]
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||
|
||||
@@ -464,7 +466,7 @@ proc mergeShadowScope*(c: PContext) =
|
||||
c.addInterfaceDecl(sym)
|
||||
|
||||
|
||||
import std/editdistance, heapqueue
|
||||
import std/[editdistance, heapqueue]
|
||||
|
||||
type SpellCandidate = object
|
||||
dist: int
|
||||
|
||||
@@ -144,7 +144,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
|
||||
result.add newFastAsgnStmt(n[2], tempAsNode)
|
||||
|
||||
proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType =
|
||||
result = newType(tyObject, nextTypeId(idgen), owner)
|
||||
result = newType(tyObject, idgen, owner)
|
||||
if final:
|
||||
rawAddSon(result, nil)
|
||||
incl result.flags, tfFinal
|
||||
@@ -320,7 +320,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
|
||||
proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
|
||||
result = newNodeI(nkAddr, n.info, 1)
|
||||
result[0] = n
|
||||
result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner)
|
||||
result.typ = newType(typeKind, idgen, n.typ.owner)
|
||||
result.typ.rawAddSon(n.typ)
|
||||
|
||||
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
|
||||
|
||||
@@ -18,7 +18,7 @@ export createMagic
|
||||
proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
|
||||
|
||||
proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
|
||||
result = newType(kind, nextTypeId(g.idgen), g.systemModule)
|
||||
result = newType(kind, g.idgen, g.systemModule)
|
||||
result.size = size
|
||||
result.align = size.int16
|
||||
|
||||
@@ -27,7 +27,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
|
||||
if result == nil:
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
result.typ = newType(tyError, g.idgen, g.systemModule)
|
||||
|
||||
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
|
||||
result = nil
|
||||
@@ -40,7 +40,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
|
||||
if result != nil: return result
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
|
||||
result.typ = newType(tyError, g.idgen, g.systemModule)
|
||||
|
||||
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
|
||||
result = getSysSym(g, info, name).typ
|
||||
@@ -93,7 +93,7 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
|
||||
|
||||
proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
|
||||
if t.n != nil and t.kind in {tyInt, tyFloat}:
|
||||
result = copyType(t, nextTypeId(id), t.owner)
|
||||
result = copyType(t, id, t.owner)
|
||||
result.n = nil
|
||||
else:
|
||||
result = t
|
||||
@@ -150,4 +150,13 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
|
||||
globalError(g.config, info,
|
||||
"can't find magic equals operator for type kind " & $t.kind)
|
||||
|
||||
proc makePtrType*(baseType: PType; idgen: IdGenerator): PType =
|
||||
result = newType(tyPtr, idgen, baseType.owner)
|
||||
addSonSkipIntLit(result, baseType, idgen)
|
||||
|
||||
proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
|
||||
if n.kind == nkHiddenAddr:
|
||||
result = n
|
||||
else:
|
||||
result = newTree(nkHiddenAddr, n)
|
||||
result.typ = makePtrType(n.typ, idgen)
|
||||
|
||||
@@ -22,12 +22,13 @@ import
|
||||
modules,
|
||||
modulegraphs, lineinfos, pathutils, vmprofiler
|
||||
|
||||
# ensure NIR compiles:
|
||||
import nir / nir
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import ic / [cbackend, integrity, navigator]
|
||||
from ic / ic import rodViewer
|
||||
import ic / [cbackend, integrity, navigator, ic]
|
||||
|
||||
import ../dist/checksums/src/checksums/sha1
|
||||
|
||||
@@ -47,6 +48,9 @@ proc writeDepsFile(g: ModuleGraph) =
|
||||
f.writeLine(toFullPath(g.config, k))
|
||||
f.close()
|
||||
|
||||
proc writeNinjaFile(g: ModuleGraph) =
|
||||
discard "to implement"
|
||||
|
||||
proc writeCMakeDepsFile(conf: ConfigRef) =
|
||||
## write a list of C files for build systems like CMake.
|
||||
## only updated when the C file list changes.
|
||||
@@ -157,6 +161,26 @@ proc commandCompileToC(graph: ModuleGraph) =
|
||||
if optGenCDeps in graph.config.globalOptions:
|
||||
writeCMakeDepsFile(conf)
|
||||
|
||||
proc commandCompileToNir(graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
extccomp.initVars(conf)
|
||||
if conf.symbolFiles == disabledSf:
|
||||
if {optRun, optForceFullMake} * conf.globalOptions == {optRun}:
|
||||
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
|
||||
# nothing changed
|
||||
graph.config.notes = graph.config.mainPackageNotes
|
||||
return
|
||||
|
||||
if not extccomp.ccHasSaneOverflow(conf):
|
||||
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
|
||||
|
||||
if conf.symbolFiles == disabledSf:
|
||||
setPipeLinePass(graph, NirPass)
|
||||
else:
|
||||
setPipeLinePass(graph, SemPass)
|
||||
compilePipelineProject(graph)
|
||||
writeNinjaFile(graph)
|
||||
|
||||
proc commandJsonScript(graph: ModuleGraph) =
|
||||
extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile)
|
||||
|
||||
@@ -173,13 +197,16 @@ proc commandCompileToJS(graph: ModuleGraph) =
|
||||
if optGenScript in conf.globalOptions:
|
||||
writeDepsFile(graph)
|
||||
|
||||
proc commandInteractive(graph: ModuleGraph) =
|
||||
proc commandInteractive(graph: ModuleGraph; useNir: bool) =
|
||||
graph.config.setErrorMaxHighMaybe
|
||||
initDefines(graph.config.symbols)
|
||||
defineSymbol(graph.config.symbols, "nimscript")
|
||||
if useNir:
|
||||
defineSymbol(graph.config.symbols, "noSignalHandler")
|
||||
else:
|
||||
defineSymbol(graph.config.symbols, "nimscript")
|
||||
# note: seems redundant with -d:nimHasLibFFI
|
||||
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
|
||||
setPipeLinePass(graph, InterpreterPass)
|
||||
setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass)
|
||||
compilePipelineSystemModule(graph)
|
||||
if graph.config.commandArgs.len > 0:
|
||||
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
|
||||
@@ -267,6 +294,8 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
# and it has added this define implictly, so we must undo that here.
|
||||
# A better solution might be to fix system.nim
|
||||
undefSymbol(conf.symbols, "useNimRtl")
|
||||
of backendNir:
|
||||
if conf.exc == excNone: conf.exc = excGoto
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
proc compileToBackend() =
|
||||
@@ -277,6 +306,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
of backendCpp: commandCompileToC(graph)
|
||||
of backendObjc: commandCompileToC(graph)
|
||||
of backendJs: commandCompileToJS(graph)
|
||||
of backendNir: commandCompileToNir(graph)
|
||||
of backendInvalid: raiseAssert "unreachable"
|
||||
|
||||
template docLikeCmd(body) =
|
||||
@@ -304,7 +334,10 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
|
||||
## process all commands
|
||||
case conf.cmd
|
||||
of cmdBackends: compileToBackend()
|
||||
of cmdBackends:
|
||||
compileToBackend()
|
||||
when BenchIC:
|
||||
echoTimes graph.packed
|
||||
of cmdTcc:
|
||||
when hasTinyCBackend:
|
||||
extccomp.setCC(conf, "tcc", unknownLineInfo)
|
||||
@@ -400,6 +433,10 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
for it in conf.searchPaths: msgWriteln(conf, it.string)
|
||||
of cmdCheck:
|
||||
commandCheck(graph)
|
||||
of cmdM:
|
||||
graph.config.symbolFiles = v2Sf
|
||||
setUseIc(graph.config.symbolFiles != disabledSf)
|
||||
commandCheck(graph)
|
||||
of cmdParse:
|
||||
wantMainModule(conf)
|
||||
discard parseFile(conf.projectMainIdx, cache, conf)
|
||||
@@ -407,7 +444,7 @@ proc mainCommand*(graph: ModuleGraph) =
|
||||
wantMainModule(conf)
|
||||
commandView(graph)
|
||||
#msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
|
||||
of cmdInteractive: commandInteractive(graph)
|
||||
of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir"))
|
||||
of cmdNimscript:
|
||||
if conf.projectIsCmd or conf.projectIsStdin: discard
|
||||
elif not fileExists(conf.projectFull):
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
## represents a complete Nim project. Single modules can either be kept in RAM
|
||||
## or stored in a rod-file.
|
||||
|
||||
import intsets, tables, hashes
|
||||
import std/[intsets, tables, hashes]
|
||||
import ../dist/checksums/src/checksums/md5
|
||||
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
|
||||
import ic / [packed_ast, ic]
|
||||
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -57,6 +58,7 @@ type
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
isDecl*: bool
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
@@ -65,6 +67,8 @@ type
|
||||
CgenPass
|
||||
EvalPass
|
||||
InterpreterPass
|
||||
NirPass
|
||||
NirReplPass
|
||||
GenDependPass
|
||||
Docgen2TexPass
|
||||
Docgen2JsonPass
|
||||
@@ -78,8 +82,9 @@ type
|
||||
typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
|
||||
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
|
||||
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
|
||||
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
|
||||
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
|
||||
methodsPerGenericType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
|
||||
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual,member and ctor so far).
|
||||
initializersPerType*: Table[ItemId, PNode] # Type ID, AST call to the default ctor (c++ only)
|
||||
enumToStringProcs*: Table[ItemId, LazySym]
|
||||
emittedTypeInfo*: Table[string, FileIndex]
|
||||
|
||||
@@ -89,6 +94,7 @@ type
|
||||
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
|
||||
suggestMode*: bool # whether we are in nimsuggest mode or not.
|
||||
invalidTransitiveClosure: bool
|
||||
interactive*: bool
|
||||
inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
|
||||
# first module that included it
|
||||
importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive
|
||||
@@ -98,12 +104,18 @@ type
|
||||
cache*: IdentCache
|
||||
vm*: RootRef # unfortunately the 'vm' state is shared project-wise, this will
|
||||
# be clarified in later compiler implementations.
|
||||
repl*: RootRef # REPL state is shared project-wise.
|
||||
doStopCompile*: proc(): bool {.closure.}
|
||||
usageSym*: PSym # for nimsuggest
|
||||
owners*: seq[PSym]
|
||||
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
|
||||
suggestErrors*: Table[FileIndex, seq[Suggest]]
|
||||
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
|
||||
bucketTable*: CountTable[ItemId]
|
||||
objectTree*: Table[ItemId, seq[tuple[depth: int, value: PType]]]
|
||||
methodsPerType*: Table[ItemId, seq[LazySym]]
|
||||
dispatchers*: seq[LazySym]
|
||||
|
||||
systemModule*: PSym
|
||||
sysTypes*: array[TTypeKind, PType]
|
||||
compilerprocs*: TStrTable
|
||||
@@ -147,8 +159,10 @@ proc resetForBackend*(g: ModuleGraph) =
|
||||
g.procInstCache.clear()
|
||||
for a in mitems(g.attachedOps):
|
||||
a.clear()
|
||||
g.methodsPerType.clear()
|
||||
g.methodsPerGenericType.clear()
|
||||
g.enumToStringProcs.clear()
|
||||
g.dispatchers.setLen(0)
|
||||
g.methodsPerType.clear()
|
||||
|
||||
const
|
||||
cb64 = [
|
||||
@@ -206,10 +220,10 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
|
||||
proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
|
||||
result = module < g.packed.len and g.packed[module].status == loaded
|
||||
|
||||
proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
|
||||
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
|
||||
isCachedModule(g, m.position)
|
||||
|
||||
proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
|
||||
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
|
||||
when false:
|
||||
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
|
||||
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
|
||||
@@ -319,6 +333,7 @@ iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
|
||||
for t in mitems(x[]):
|
||||
yield resolveInst(g, t)
|
||||
|
||||
|
||||
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
|
||||
## returns the requested attached operation for type `t`. Can return nil
|
||||
## if no such operation exists.
|
||||
@@ -342,6 +357,27 @@ proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttached
|
||||
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
|
||||
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
|
||||
|
||||
iterator getDispatchers*(g: ModuleGraph): PSym =
|
||||
for i in g.dispatchers.mitems:
|
||||
yield resolveSym(g, i)
|
||||
|
||||
proc addDispatchers*(g: ModuleGraph, value: PSym) =
|
||||
# TODO: add it for packed modules
|
||||
g.dispatchers.add LazySym(sym: value)
|
||||
|
||||
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[LazySym]): PSym =
|
||||
for it in list.mitems:
|
||||
yield resolveSym(g, it)
|
||||
|
||||
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[LazySym]) =
|
||||
# TODO: add it for packed modules
|
||||
g.methodsPerType[id] = methods
|
||||
|
||||
iterator getMethodsPerType*(g: ModuleGraph; t: PType): PSym =
|
||||
if g.methodsPerType.contains(t.itemId):
|
||||
for it in mitems g.methodsPerType[t.itemId]:
|
||||
yield resolveSym(g, it)
|
||||
|
||||
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
|
||||
result = resolveSym(g, g.enumToStringProcs[t.itemId])
|
||||
assert result != nil
|
||||
@@ -350,12 +386,12 @@ proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
|
||||
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
|
||||
|
||||
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
|
||||
if g.methodsPerType.contains(t.itemId):
|
||||
for it in mitems g.methodsPerType[t.itemId]:
|
||||
if g.methodsPerGenericType.contains(t.itemId):
|
||||
for it in mitems g.methodsPerGenericType[t.itemId]:
|
||||
yield (it[0], resolveSym(g, it[1]))
|
||||
|
||||
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
|
||||
g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
|
||||
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
|
||||
|
||||
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
|
||||
let op = getAttachedOp(g, t, attachedAsgn)
|
||||
@@ -372,7 +408,7 @@ proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
if g.config.symbolFiles == disabledSf: return nil
|
||||
|
||||
# slow, linear search, but the results are cached:
|
||||
for module in 0..high(g.packed):
|
||||
for module in 0..<len(g.packed):
|
||||
#if isCachedModule(g, module):
|
||||
let x = searchForCompilerproc(g.packed[module], name)
|
||||
if x >= 0:
|
||||
@@ -429,7 +465,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
|
||||
setLen(g.ifaces, m.position + 1)
|
||||
|
||||
if m.position >= g.packed.len:
|
||||
setLen(g.packed, m.position + 1)
|
||||
setLen(g.packed.pm, m.position + 1)
|
||||
|
||||
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
|
||||
uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
|
||||
@@ -581,6 +617,7 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||
if m != nil:
|
||||
g.suggestSymbols.del(fileIdx)
|
||||
g.suggestErrors.del(fileIdx)
|
||||
g.resetForBackend
|
||||
incl m.flags, sfDirty
|
||||
|
||||
proc unmarkAllDirty*(g: ModuleGraph) =
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
|
||||
import ast, renderer, msgs, options, idents, lineinfos,
|
||||
pathutils
|
||||
|
||||
import std/[strutils, os]
|
||||
|
||||
proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
# This returns a short relative module name without the nim extension
|
||||
# e.g. like "system", "importer" or "somepath/module"
|
||||
|
||||
@@ -726,6 +726,8 @@ proc genSuccessX*(conf: ConfigRef) =
|
||||
elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends:
|
||||
# for some cmd we expect a valid absOutFile
|
||||
output = "unknownOutput"
|
||||
elif optStdout in conf.globalOptions:
|
||||
output = "stdout"
|
||||
else:
|
||||
output = $conf.absOutFile
|
||||
if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes
|
||||
import sequtils, strutils, sets
|
||||
import ast, renderer, msgs, options, lineinfos, idents, treetab
|
||||
import std/[intsets, tables, sequtils, strutils, sets, strformat, hashes]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -918,7 +918,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
|
||||
newSymNode(op, r.info),
|
||||
l,
|
||||
r)
|
||||
result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
|
||||
result.typ = newType(tyBool, ctx.idgen, nil)
|
||||
|
||||
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
var cache = newIdentCache()
|
||||
@@ -928,7 +928,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
|
||||
result = nkPrefix.newTree(
|
||||
newSymNode(op, node.info),
|
||||
node)
|
||||
result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
|
||||
result.typ = newType(tyBool, ctx.idgen, nil)
|
||||
|
||||
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
|
||||
infix(ctx, l, r, mEqRef)
|
||||
|
||||
@@ -9,6 +9,7 @@ define:nimPreviewSlimSystem
|
||||
define:nimPreviewCstringConversion
|
||||
define:nimPreviewProcConversion
|
||||
define:nimPreviewRangeDefault
|
||||
define:nimPreviewNonVarDestructor
|
||||
threads:off
|
||||
|
||||
#import:"$projectpath/testability"
|
||||
@@ -41,6 +42,7 @@ define:useStdoutAsStdmsg
|
||||
@end
|
||||
|
||||
@if nimHasWarnBareExcept:
|
||||
warning[BareExcept]:on
|
||||
warningAserror[BareExcept]:on
|
||||
@end
|
||||
|
||||
@@ -51,6 +53,11 @@ define:useStdoutAsStdmsg
|
||||
#warningAsError[ProveInit]:on
|
||||
@end
|
||||
|
||||
@if nimHasQuirkyBoots:
|
||||
exceptions:quirky
|
||||
@if nimHasWarnStdPrefix:
|
||||
warning[StdPrefix]:on
|
||||
warningAsError[StdPrefix]:on
|
||||
@end
|
||||
|
||||
@if nimHasVtables:
|
||||
experimental:vtables
|
||||
@end
|
||||
|
||||
@@ -28,7 +28,7 @@ import
|
||||
commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper,
|
||||
pathutils, modulegraphs
|
||||
|
||||
from browsers import openDefaultBrowser
|
||||
from std/browsers import openDefaultBrowser
|
||||
from nodejs import findNodeJs
|
||||
|
||||
when hasTinyCBackend:
|
||||
@@ -116,7 +116,8 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
conf.backend = backendC
|
||||
|
||||
if conf.selectedGC == gcUnselected:
|
||||
if conf.backend in {backendC, backendCpp, backendObjc}:
|
||||
if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
|
||||
(conf.cmd == cmdInteractive and isDefined(conf, "nir")):
|
||||
initOrcDefines(conf)
|
||||
|
||||
mainCommand(graph)
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||
|
||||
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
|
||||
tables
|
||||
import options, msgs, lineinfos, pathutils
|
||||
|
||||
import std/[parseutils, strutils, os, tables, sequtils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
# This module handles the reading of the config file.
|
||||
|
||||
import
|
||||
llstream, commands, os, strutils, msgs, lexer, ast,
|
||||
options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig
|
||||
llstream, commands, msgs, lexer, ast,
|
||||
options, idents, wordrecg, lineinfos, pathutils, scriptconfig
|
||||
|
||||
import std/[os, strutils, strtabs]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/syncio
|
||||
@@ -162,7 +164,7 @@ proc checkSymbol(L: Lexer, tok: Token) =
|
||||
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
|
||||
|
||||
proc parseAssignment(L: var Lexer, tok: var Token;
|
||||
config: ConfigRef; condStack: var seq[bool]) =
|
||||
config: ConfigRef; filename: AbsoluteFile; condStack: var seq[bool]) =
|
||||
if tok.ident != nil:
|
||||
if tok.ident.s == "-" or tok.ident.s == "--":
|
||||
confTok(L, tok, config, condStack) # skip unnecessary prefix
|
||||
@@ -205,6 +207,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
|
||||
checkSymbol(L, tok)
|
||||
val.add($tok)
|
||||
confTok(L, tok, config, condStack)
|
||||
config.currentConfigDir = parentDir(filename.string)
|
||||
if percent:
|
||||
processSwitch(s, strtabs.`%`(val, config.configVars,
|
||||
{useEnvironment, useEmpty}), passPP, info, config)
|
||||
@@ -224,7 +227,7 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
|
||||
tok.tokType = tkEof # to avoid a pointless warning
|
||||
var condStack: seq[bool] = @[]
|
||||
confTok(L, tok, config, condStack) # read in the first token
|
||||
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
|
||||
while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack)
|
||||
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
|
||||
closeLexer(L)
|
||||
return true
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
# handling that exists! Only at line endings checks are necessary
|
||||
# if the buffer needs refilling.
|
||||
|
||||
import
|
||||
llstream, strutils
|
||||
import llstream
|
||||
|
||||
import std/strutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -17,7 +17,7 @@ interpolation variables:
|
||||
Unstable API
|
||||
]##
|
||||
|
||||
import os, strutils
|
||||
import std/[os, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
2645
compiler/nir/ast2ir.nim
Normal file
2645
compiler/nir/ast2ir.nim
Normal file
File diff suppressed because it is too large
Load Diff
983
compiler/nir/cir.nim
Normal file
983
compiler/nir/cir.nim
Normal file
@@ -0,0 +1,983 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# We produce C code as a list of tokens.
|
||||
|
||||
import std / [assertions, syncio, tables, intsets, formatfloat]
|
||||
from std / strutils import toOctal
|
||||
import .. / ic / [bitabs, rodfiles]
|
||||
import nirtypes, nirinsts, nirfiles
|
||||
import ../../dist/checksums/src/checksums/md5
|
||||
|
||||
type
|
||||
Token = LitId # indexing into the tokens BiTable[string]
|
||||
|
||||
PredefinedToken = enum
|
||||
IgnoreMe = "<unused>"
|
||||
EmptyToken = ""
|
||||
CurlyLe = "{"
|
||||
CurlyRi = "}"
|
||||
ParLe = "("
|
||||
ParRi = ")"
|
||||
BracketLe = "["
|
||||
BracketRi = "]"
|
||||
NewLine = "\n"
|
||||
Semicolon = ";"
|
||||
Comma = ", "
|
||||
Space = " "
|
||||
Colon = ": "
|
||||
Dot = "."
|
||||
Arrow = "->"
|
||||
Star = "*"
|
||||
Amp = "&"
|
||||
AsgnOpr = " = "
|
||||
ScopeOpr = "::"
|
||||
ConstKeyword = "const "
|
||||
StaticKeyword = "static "
|
||||
ExternKeyword = "extern "
|
||||
WhileKeyword = "while "
|
||||
IfKeyword = "if ("
|
||||
ElseKeyword = "else "
|
||||
SwitchKeyword = "switch "
|
||||
CaseKeyword = "case "
|
||||
DefaultKeyword = "default:"
|
||||
BreakKeyword = "break"
|
||||
NullPtr = "nullptr"
|
||||
IfNot = "if (!("
|
||||
ReturnKeyword = "return "
|
||||
TypedefStruct = "typedef struct "
|
||||
TypedefUnion = "typedef union "
|
||||
IncludeKeyword = "#include "
|
||||
|
||||
proc fillTokenTable(tab: var BiTable[string]) =
|
||||
for e in EmptyToken..high(PredefinedToken):
|
||||
let id = tab.getOrIncl $e
|
||||
assert id == LitId(e), $(id, " ", ord(e))
|
||||
|
||||
type
|
||||
GeneratedCode* = object
|
||||
m: NirModule
|
||||
includes: seq[LitId]
|
||||
includedHeaders: IntSet
|
||||
data: seq[LitId]
|
||||
protos: seq[LitId]
|
||||
code: seq[LitId]
|
||||
init: seq[LitId]
|
||||
tokens: BiTable[string]
|
||||
emittedStrings: IntSet
|
||||
needsPrefix: IntSet
|
||||
generatedTypes: IntSet
|
||||
mangledModules: Table[LitId, LitId]
|
||||
|
||||
proc initGeneratedCode*(m: sink NirModule): GeneratedCode =
|
||||
result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]())
|
||||
fillTokenTable(result.tokens)
|
||||
|
||||
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
|
||||
g.code.add Token(t)
|
||||
|
||||
proc add*(g: var GeneratedCode; s: string) {.inline.} =
|
||||
g.code.add g.tokens.getOrIncl(s)
|
||||
|
||||
proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId =
|
||||
result = c.mangledModules.getOrDefault(key, LitId(0))
|
||||
if result == LitId(0):
|
||||
let u {.cursor.} = c.m.lit.strings[key]
|
||||
var last = u.len - len(".nim") - 1
|
||||
var start = last
|
||||
while start >= 0 and u[start] != '/': dec start
|
||||
var sum = getMD5(u)
|
||||
sum.setLen(8)
|
||||
let dest = u.substr(start+1, last) & sum
|
||||
result = c.tokens.getOrIncl(dest)
|
||||
c.mangledModules[key] = result
|
||||
|
||||
type
|
||||
CppFile = object
|
||||
f: File
|
||||
|
||||
proc write(f: var CppFile; s: string) = write(f.f, s)
|
||||
proc write(f: var CppFile; c: char) = write(f.f, c)
|
||||
|
||||
proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) =
|
||||
var indent = 0
|
||||
for i in 0..<s.len:
|
||||
let x = s[i]
|
||||
case x
|
||||
of Token(CurlyLe):
|
||||
inc indent
|
||||
write f, c.tokens[x]
|
||||
write f, "\n"
|
||||
for i in 1..indent*2: write f, ' '
|
||||
of Token(CurlyRi):
|
||||
dec indent
|
||||
write f, c.tokens[x]
|
||||
if i+1 < s.len and s[i+1] == Token(CurlyRi):
|
||||
discard
|
||||
else:
|
||||
write f, "\n"
|
||||
for i in 1..indent*2: write f, ' '
|
||||
of Token(Semicolon):
|
||||
write f, c.tokens[x]
|
||||
if i+1 < s.len and s[i+1] == Token(CurlyRi):
|
||||
discard "no newline before }"
|
||||
else:
|
||||
write f, "\n"
|
||||
for i in 1..indent*2: write f, ' '
|
||||
of Token(NewLine):
|
||||
write f, c.tokens[x]
|
||||
for i in 1..indent*2: write f, ' '
|
||||
else:
|
||||
write f, c.tokens[x]
|
||||
|
||||
|
||||
# Type graph
|
||||
|
||||
type
|
||||
TypeList = object
|
||||
processed: IntSet
|
||||
s: seq[(TypeId, PredefinedToken)]
|
||||
|
||||
proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) =
|
||||
if not containsOrIncl(dest.processed, int(elem)):
|
||||
dest.s.add (elem, decl)
|
||||
|
||||
type
|
||||
TypeOrder = object
|
||||
forwardedDecls, ordered: TypeList
|
||||
typeImpls: Table[string, TypeId]
|
||||
lookedAt: IntSet
|
||||
|
||||
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId)
|
||||
|
||||
proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) =
|
||||
var ch = child
|
||||
var viaPointer = false
|
||||
while true:
|
||||
case types[ch].kind
|
||||
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
|
||||
viaPointer = true
|
||||
ch = elementType(types, ch)
|
||||
of LastArrayTy:
|
||||
ch = elementType(types, ch)
|
||||
else:
|
||||
break
|
||||
|
||||
case types[ch].kind
|
||||
of ObjectTy, UnionTy:
|
||||
let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion
|
||||
let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId])
|
||||
if viaPointer:
|
||||
c.forwardedDecls.add obj, decl
|
||||
else:
|
||||
if not containsOrIncl(c.lookedAt, obj.int):
|
||||
traverseObject(types, lit, c, obj)
|
||||
c.ordered.add obj, decl
|
||||
of ArrayTy:
|
||||
if viaPointer:
|
||||
c.forwardedDecls.add ch, TypedefStruct
|
||||
else:
|
||||
if not containsOrIncl(c.lookedAt, ch.int):
|
||||
traverseObject(types, lit, c, ch)
|
||||
c.ordered.add ch, TypedefStruct
|
||||
else:
|
||||
discard "uninteresting type as we only focus on the required struct declarations"
|
||||
|
||||
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) =
|
||||
for x in sons(types, t):
|
||||
case types[x].kind
|
||||
of FieldDecl:
|
||||
recordDependency types, lit, c, t, x.firstSon
|
||||
of ObjectTy:
|
||||
# inheritance
|
||||
recordDependency types, lit, c, t, x
|
||||
else: discard
|
||||
|
||||
proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) =
|
||||
for t in allTypes(types):
|
||||
if types[t].kind in {ObjectDecl, UnionDecl}:
|
||||
assert types[t.firstSon].kind == NameVal
|
||||
c.typeImpls[lit.strings[types[t.firstSon].litId]] = t
|
||||
|
||||
for t in allTypesIncludingInner(types):
|
||||
case types[t].kind
|
||||
of ObjectDecl, UnionDecl:
|
||||
traverseObject types, lit, c, t
|
||||
let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion
|
||||
c.ordered.add t, decl
|
||||
of ArrayTy:
|
||||
traverseObject types, lit, c, t
|
||||
c.ordered.add t, TypedefStruct
|
||||
else: discard
|
||||
|
||||
when false:
|
||||
template emitType(s: string) = c.types.add c.tokens.getOrIncl(s)
|
||||
template emitType(t: Token) = c.types.add t
|
||||
template emitType(t: PredefinedToken) = c.types.add Token(t)
|
||||
|
||||
proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") =
|
||||
template maybeAddName =
|
||||
if name != "":
|
||||
g.add Space
|
||||
g.add name
|
||||
|
||||
template atom(s: string) =
|
||||
g.add s
|
||||
maybeAddName()
|
||||
case types[t].kind
|
||||
of VoidTy: atom "void"
|
||||
of IntTy: atom "NI" & $types[t].integralBits
|
||||
of UIntTy: atom "NU" & $types[t].integralBits
|
||||
of FloatTy: atom "NF" & $types[t].integralBits
|
||||
of BoolTy: atom "NB" & $types[t].integralBits
|
||||
of CharTy: atom "NC" & $types[t].integralBits
|
||||
of ObjectTy, UnionTy, NameVal, AnnotationVal:
|
||||
atom lit.strings[types[t].litId]
|
||||
of VarargsTy:
|
||||
g.add "..."
|
||||
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
|
||||
genType g, types, lit, elementType(types, t)
|
||||
g.add Star
|
||||
maybeAddName()
|
||||
of ArrayTy:
|
||||
genType g, types, lit, arrayName(types, t)
|
||||
maybeAddName()
|
||||
of LastArrayTy:
|
||||
genType g, types, lit, elementType(types, t)
|
||||
maybeAddName()
|
||||
g.add BracketLe
|
||||
g.add BracketRi
|
||||
of ProcTy:
|
||||
let (retType, callConv) = returnType(types, t)
|
||||
genType g, types, lit, retType
|
||||
g.add Space
|
||||
g.add ParLe
|
||||
genType g, types, lit, callConv
|
||||
g.add Star # "(*fn)"
|
||||
maybeAddName()
|
||||
g.add ParRi
|
||||
g.add ParLe
|
||||
var i = 0
|
||||
for ch in params(types, t):
|
||||
if i > 0: g.add Comma
|
||||
genType g, types, lit, ch
|
||||
inc i
|
||||
g.add ParRi
|
||||
of ObjectDecl, UnionDecl:
|
||||
atom lit.strings[types[t.firstSon].litId]
|
||||
of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl:
|
||||
#raiseAssert "did not expect: " & $types[t].kind
|
||||
g.add "BUG "
|
||||
atom $types[t].kind
|
||||
|
||||
proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) =
|
||||
for (t, declKeyword) in c.forwardedDecls.s:
|
||||
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
|
||||
let s {.cursor.} = lit.strings[types[name].litId]
|
||||
g.add declKeyword
|
||||
g.add s
|
||||
g.add Space
|
||||
g.add s
|
||||
g.add Semicolon
|
||||
|
||||
for (t, declKeyword) in c.ordered.s:
|
||||
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
|
||||
let litId = types[name].litId
|
||||
if not g.generatedTypes.containsOrIncl(litId.int):
|
||||
let s {.cursor.} = lit.strings[litId]
|
||||
g.add declKeyword
|
||||
g.add CurlyLe
|
||||
if types[t].kind == ArrayTy:
|
||||
genType g, types, lit, elementType(types, t), "a"
|
||||
g.add BracketLe
|
||||
g.add $arrayLen(types, t)
|
||||
g.add BracketRi
|
||||
g.add Semicolon
|
||||
else:
|
||||
var i = 0
|
||||
for x in sons(types, t):
|
||||
case types[x].kind
|
||||
of FieldDecl:
|
||||
genType g, types, lit, x.firstSon, "F" & $i
|
||||
g.add Semicolon
|
||||
inc i
|
||||
of ObjectTy:
|
||||
genType g, types, lit, x, "P"
|
||||
g.add Semicolon
|
||||
else: discard
|
||||
g.add CurlyRi
|
||||
g.add s
|
||||
g.add Semicolon
|
||||
|
||||
# Procs
|
||||
|
||||
proc toCChar*(c: char; result: var string) {.inline.} =
|
||||
case c
|
||||
of '\0'..'\x1F', '\x7F'..'\xFF':
|
||||
result.add '\\'
|
||||
result.add toOctal(c)
|
||||
of '\'', '\"', '\\', '?':
|
||||
result.add '\\'
|
||||
result.add c
|
||||
else:
|
||||
result.add c
|
||||
|
||||
proc makeCString(s: string): string =
|
||||
result = newStringOfCap(s.len + 10)
|
||||
result.add('"')
|
||||
for c in s: toCChar(c, result)
|
||||
result.add('"')
|
||||
|
||||
template emitData(s: string) = c.data.add c.tokens.getOrIncl(s)
|
||||
template emitData(t: Token) = c.data.add t
|
||||
template emitData(t: PredefinedToken) = c.data.add Token(t)
|
||||
|
||||
proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token =
|
||||
result = Token(c.tokens.getOrIncl "QStr" & $litId)
|
||||
if not containsOrIncl(c.emittedStrings, int(litId)):
|
||||
let s {.cursor.} = lit.strings[litId]
|
||||
emitData "static const struct "
|
||||
emitData CurlyLe
|
||||
emitData "NI cap"
|
||||
emitData Semicolon
|
||||
emitData "NC8 data"
|
||||
emitData BracketLe
|
||||
emitData $s.len
|
||||
emitData "+1"
|
||||
emitData BracketRi
|
||||
emitData Semicolon
|
||||
emitData CurlyRi
|
||||
emitData result
|
||||
emitData AsgnOpr
|
||||
emitData CurlyLe
|
||||
emitData $s.len
|
||||
emitData " | NIM_STRLIT_FLAG"
|
||||
emitData Comma
|
||||
emitData makeCString(s)
|
||||
emitData CurlyRi
|
||||
emitData Semicolon
|
||||
|
||||
proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) =
|
||||
let i = lit.numbers[litId]
|
||||
if i > low(int32) and i <= high(int32):
|
||||
c.add $i
|
||||
elif i == low(int32):
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
c.add "(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
c.add "IL64("
|
||||
c.add $i
|
||||
c.add ")"
|
||||
else:
|
||||
c.add "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc gen(c: var GeneratedCode; t: Tree; n: NodePos)
|
||||
|
||||
proc genDisplayName(c: var GeneratedCode; symId: SymId) =
|
||||
let displayName = c.m.symnames[symId]
|
||||
if displayName != LitId(0):
|
||||
c.add "/*"
|
||||
c.add c.m.lit.strings[displayName]
|
||||
c.add "*/"
|
||||
|
||||
proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) =
|
||||
if t[n].kind == SymDef:
|
||||
let symId = t[n].symId
|
||||
c.needsPrefix.incl symId.int
|
||||
genDisplayName c, symId
|
||||
gen c, t, n
|
||||
|
||||
proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
|
||||
c.add annotation
|
||||
let m: string
|
||||
if t[name].kind == SymDef:
|
||||
let symId = t[name].symId
|
||||
m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId
|
||||
genDisplayName c, symId
|
||||
else:
|
||||
assert t[name].kind == ModuleSymUse
|
||||
let (x, y) = sons2(t, name)
|
||||
m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal
|
||||
genType c, c.m.types, c.m.lit, t[typ].typeId, m
|
||||
|
||||
proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
|
||||
assert t[name].kind == SymDef
|
||||
c.add annotation
|
||||
let symId = t[name].symId
|
||||
genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId
|
||||
genDisplayName c, symId
|
||||
|
||||
proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) =
|
||||
let signatureBegin = c.code.len
|
||||
let name = n.firstSon
|
||||
|
||||
var prc = n.firstSon
|
||||
next t, prc
|
||||
|
||||
while true:
|
||||
case t[prc].kind
|
||||
of PragmaPair:
|
||||
let (x, y) = sons2(t, prc)
|
||||
let key = cast[PragmaKey](t[x].rawOperand)
|
||||
case key
|
||||
of HeaderImport:
|
||||
let lit = t[y].litId
|
||||
let headerAsStr {.cursor.} = c.m.lit.strings[lit]
|
||||
let header = c.tokens.getOrIncl(headerAsStr)
|
||||
# headerAsStr can be empty, this has the semantics of the `nodecl` pragma:
|
||||
if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header):
|
||||
if headerAsStr[0] == '#':
|
||||
discard "skip the #include"
|
||||
else:
|
||||
c.includes.add Token(IncludeKeyword)
|
||||
c.includes.add header
|
||||
c.includes.add Token NewLine
|
||||
# do not generate code for importc'ed procs:
|
||||
return
|
||||
of DllImport:
|
||||
let lit = t[y].litId
|
||||
raiseAssert "cannot eval: " & c.m.lit.strings[lit]
|
||||
else: discard
|
||||
of PragmaId: discard
|
||||
else: break
|
||||
next t, prc
|
||||
|
||||
var resultDeclPos = NodePos(-1)
|
||||
if t[prc].kind == SummonResult:
|
||||
resultDeclPos = prc
|
||||
gen c, t, prc.firstSon
|
||||
next t, prc
|
||||
else:
|
||||
c.add "void"
|
||||
c.add Space
|
||||
genSymDef c, t, name
|
||||
c.add ParLe
|
||||
var params = 0
|
||||
while t[prc].kind == SummonParam:
|
||||
if params > 0: c.add Comma
|
||||
let (typ, sym) = sons2(t, prc)
|
||||
genLocal c, t, sym, typ, ""
|
||||
next t, prc
|
||||
inc params
|
||||
if params == 0:
|
||||
c.add "void"
|
||||
c.add ParRi
|
||||
|
||||
for i in signatureBegin ..< c.code.len:
|
||||
c.protos.add c.code[i]
|
||||
c.protos.add Token Semicolon
|
||||
|
||||
if isExtern:
|
||||
c.code.setLen signatureBegin
|
||||
else:
|
||||
c.add CurlyLe
|
||||
if resultDeclPos.int >= 0:
|
||||
gen c, t, resultDeclPos
|
||||
for ch in sonsRest(t, n, prc):
|
||||
gen c, t, ch
|
||||
c.add CurlyRi
|
||||
|
||||
template triop(opr) =
|
||||
let (typ, a, b) = sons3(t, n)
|
||||
c.add ParLe
|
||||
c.add ParLe
|
||||
gen c, t, typ
|
||||
c.add ParRi
|
||||
gen c, t, a
|
||||
c.add opr
|
||||
gen c, t, b
|
||||
c.add ParRi
|
||||
|
||||
template cmpop(opr) =
|
||||
let (_, a, b) = sons3(t, n)
|
||||
c.add ParLe
|
||||
gen c, t, a
|
||||
c.add opr
|
||||
gen c, t, b
|
||||
c.add ParRi
|
||||
|
||||
template binaryop(opr) =
|
||||
let (typ, a) = sons2(t, n)
|
||||
c.add ParLe
|
||||
c.add ParLe
|
||||
gen c, t, typ
|
||||
c.add ParRi
|
||||
c.add opr
|
||||
gen c, t, a
|
||||
c.add ParRi
|
||||
|
||||
template checkedBinaryop(opr) =
|
||||
let (typ, labIdx, a, b) = sons4(t, n)
|
||||
let bits = integralBits(c.m.types[t[typ].typeId])
|
||||
let lab = t[labIdx].label
|
||||
|
||||
c.add (opr & $bits)
|
||||
c.add ParLe
|
||||
c.gen t, a
|
||||
c.add Comma
|
||||
c.gen t, b
|
||||
c.add Comma
|
||||
c.add "L" & $lab.int
|
||||
c.add ParRi
|
||||
|
||||
proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) =
|
||||
let (typ, arg) = sons2(t, n)
|
||||
if t[arg].kind == IntVal:
|
||||
let litId = t[arg].litId
|
||||
c.add ParLe
|
||||
c.add ParLe
|
||||
gen c, t, typ
|
||||
c.add ParRi
|
||||
case c.m.types[t[typ].typeId].kind
|
||||
of UIntTy:
|
||||
let x = cast[uint64](c.m.lit.numbers[litId])
|
||||
c.add $x
|
||||
of FloatTy:
|
||||
let x = cast[float64](c.m.lit.numbers[litId])
|
||||
c.add $x
|
||||
else:
|
||||
gen c, t, arg
|
||||
c.add ParRi
|
||||
else:
|
||||
binaryop ""
|
||||
|
||||
template moveToDataSection(body: untyped) =
|
||||
let oldLen = c.code.len
|
||||
body
|
||||
for i in oldLen ..< c.code.len:
|
||||
c.data.add c.code[i]
|
||||
setLen c.code, oldLen
|
||||
|
||||
proc gen(c: var GeneratedCode; t: Tree; n: NodePos) =
|
||||
case t[n].kind
|
||||
of Nop:
|
||||
discard "nothing to emit"
|
||||
of ImmediateVal:
|
||||
c.add $t[n].immediateVal
|
||||
of IntVal:
|
||||
genIntLit c, c.m.lit, t[n].litId
|
||||
of StrVal:
|
||||
c.code.add genStrLit(c, c.m.lit, t[n].litId)
|
||||
of Typed:
|
||||
genType c, c.m.types, c.m.lit, t[n].typeId
|
||||
of SymDef, SymUse:
|
||||
let s = t[n].symId
|
||||
if c.needsPrefix.contains(s.int):
|
||||
c.code.add mangleModuleName(c, c.m.namespace)
|
||||
c.add "__"
|
||||
c.add $s
|
||||
else:
|
||||
# XXX Use proper names here
|
||||
c.add "q"
|
||||
c.add $s
|
||||
|
||||
of ModuleSymUse:
|
||||
let (x, y) = sons2(t, n)
|
||||
let u = mangleModuleName(c, t[x].litId)
|
||||
let s = t[y].immediateVal
|
||||
c.code.add u
|
||||
c.add "__"
|
||||
c.add $s
|
||||
|
||||
of NilVal:
|
||||
c.add NullPtr
|
||||
of LoopLabel:
|
||||
c.add WhileKeyword
|
||||
c.add ParLe
|
||||
c.add "1"
|
||||
c.add ParRi
|
||||
c.add CurlyLe
|
||||
of GotoLoop:
|
||||
c.add CurlyRi
|
||||
of Label:
|
||||
let lab = t[n].label
|
||||
c.add "L"
|
||||
c.add $lab.int
|
||||
c.add Colon
|
||||
c.add Semicolon
|
||||
of Goto:
|
||||
let lab = t[n].label
|
||||
c.add "goto L"
|
||||
c.add $lab.int
|
||||
c.add Semicolon
|
||||
of CheckedGoto:
|
||||
discard "XXX todo"
|
||||
of ArrayConstr:
|
||||
c.add CurlyLe
|
||||
c.add ".a = "
|
||||
c.add CurlyLe
|
||||
var i = 0
|
||||
for ch in sonsFrom1(t, n):
|
||||
if i > 0: c.add Comma
|
||||
c.gen t, ch
|
||||
inc i
|
||||
c.add CurlyRi
|
||||
c.add CurlyRi
|
||||
of ObjConstr:
|
||||
c.add CurlyLe
|
||||
var i = 0
|
||||
for ch in sonsFrom1(t, n):
|
||||
if i mod 2 == 0:
|
||||
if i > 0: c.add Comma
|
||||
c.add ".F" & $t[ch].immediateVal
|
||||
c.add AsgnOpr
|
||||
else:
|
||||
c.gen t, ch
|
||||
inc i
|
||||
c.add CurlyRi
|
||||
of Ret:
|
||||
c.add ReturnKeyword
|
||||
c.gen t, n.firstSon
|
||||
c.add Semicolon
|
||||
of Select:
|
||||
c.add SwitchKeyword
|
||||
c.add ParLe
|
||||
let (_, selector) = sons2(t, n)
|
||||
c.gen t, selector
|
||||
c.add ParRi
|
||||
c.add CurlyLe
|
||||
for ch in sonsFromN(t, n, 2):
|
||||
c.gen t, ch
|
||||
c.add CurlyRi
|
||||
of SelectPair:
|
||||
let (le, ri) = sons2(t, n)
|
||||
c.gen t, le
|
||||
c.gen t, ri
|
||||
of SelectList:
|
||||
for ch in sons(t, n):
|
||||
c.gen t, ch
|
||||
of SelectValue:
|
||||
c.add CaseKeyword
|
||||
c.gen t, n.firstSon
|
||||
c.add Colon
|
||||
of SelectRange:
|
||||
let (le, ri) = sons2(t, n)
|
||||
c.add CaseKeyword
|
||||
c.gen t, le
|
||||
c.add " ... "
|
||||
c.gen t, ri
|
||||
c.add Colon
|
||||
of ForeignDecl:
|
||||
c.data.add LitId(ExternKeyword)
|
||||
c.gen t, n.firstSon
|
||||
of SummonGlobal:
|
||||
moveToDataSection:
|
||||
let (typ, sym) = sons2(t, n)
|
||||
c.genGlobal t, sym, typ, ""
|
||||
c.add Semicolon
|
||||
of SummonThreadLocal:
|
||||
moveToDataSection:
|
||||
let (typ, sym) = sons2(t, n)
|
||||
c.genGlobal t, sym, typ, "__thread "
|
||||
c.add Semicolon
|
||||
of SummonConst:
|
||||
moveToDataSection:
|
||||
let (typ, sym, val) = sons3(t, n)
|
||||
c.genGlobal t, sym, typ, "const "
|
||||
c.add AsgnOpr
|
||||
c.gen t, val
|
||||
c.add Semicolon
|
||||
of Summon, SummonResult:
|
||||
let (typ, sym) = sons2(t, n)
|
||||
c.genLocal t, sym, typ, ""
|
||||
c.add Semicolon
|
||||
|
||||
of SummonParam:
|
||||
raiseAssert "SummonParam should have been handled in genProc"
|
||||
of Kill:
|
||||
discard "we don't care about Kill instructions"
|
||||
of AddrOf:
|
||||
let (_, arg) = sons2(t, n)
|
||||
c.add "&"
|
||||
gen c, t, arg
|
||||
of DerefArrayAt:
|
||||
let (_, a, i) = sons3(t, n)
|
||||
gen c, t, a
|
||||
c.add BracketLe
|
||||
gen c, t, i
|
||||
c.add BracketRi
|
||||
of ArrayAt:
|
||||
let (_, a, i) = sons3(t, n)
|
||||
gen c, t, a
|
||||
c.add Dot
|
||||
c.add "a"
|
||||
c.add BracketLe
|
||||
gen c, t, i
|
||||
c.add BracketRi
|
||||
of FieldAt:
|
||||
let (_, a, b) = sons3(t, n)
|
||||
gen c, t, a
|
||||
let field = t[b].immediateVal
|
||||
c.add Dot
|
||||
c.add "F" & $field
|
||||
of DerefFieldAt:
|
||||
let (_, a, b) = sons3(t, n)
|
||||
gen c, t, a
|
||||
let field = t[b].immediateVal
|
||||
c.add Arrow
|
||||
c.add "F" & $field
|
||||
of Load:
|
||||
let (_, arg) = sons2(t, n)
|
||||
c.add ParLe
|
||||
c.add "*"
|
||||
gen c, t, arg
|
||||
c.add ParRi
|
||||
of Store:
|
||||
raiseAssert "Assumption was that Store is unused!"
|
||||
of Asgn:
|
||||
let (_, dest, src) = sons3(t, n)
|
||||
gen c, t, dest
|
||||
c.add AsgnOpr
|
||||
gen c, t, src
|
||||
c.add Semicolon
|
||||
of CheckedRange:
|
||||
c.add "nimCheckRange"
|
||||
c.add ParLe
|
||||
let (_, gotoInstr, x, a, b) = sons5(t, n)
|
||||
gen c, t, x
|
||||
c.add Comma
|
||||
gen c, t, a
|
||||
c.add Comma
|
||||
gen c, t, b
|
||||
c.add Comma
|
||||
c.add "L" & $t[gotoInstr].label.int
|
||||
c.add ParRi
|
||||
of CheckedIndex:
|
||||
c.add "nimCheckIndex"
|
||||
c.add ParLe
|
||||
let (gotoInstr, x, a) = sons3(t, n)
|
||||
gen c, t, x
|
||||
c.add Comma
|
||||
gen c, t, a
|
||||
c.add Comma
|
||||
c.add "L" & $t[gotoInstr].label.int
|
||||
c.add ParRi
|
||||
of Call, IndirectCall:
|
||||
let (typ, fn) = sons2(t, n)
|
||||
gen c, t, fn
|
||||
c.add ParLe
|
||||
var i = 0
|
||||
for ch in sonsFromN(t, n, 2):
|
||||
if i > 0: c.add Comma
|
||||
gen c, t, ch
|
||||
inc i
|
||||
c.add ParRi
|
||||
if c.m.types[t[typ].typeId].kind == VoidTy:
|
||||
c.add Semicolon
|
||||
of CheckedCall, CheckedIndirectCall:
|
||||
let (typ, gotoInstr, fn) = sons3(t, n)
|
||||
gen c, t, fn
|
||||
c.add ParLe
|
||||
var i = 0
|
||||
for ch in sonsFromN(t, n, 3):
|
||||
if i > 0: c.add Comma
|
||||
gen c, t, ch
|
||||
inc i
|
||||
c.add ParRi
|
||||
if c.m.types[t[typ].typeId].kind == VoidTy:
|
||||
c.add Semicolon
|
||||
|
||||
of CheckedAdd: checkedBinaryop "nimAddInt"
|
||||
of CheckedSub: checkedBinaryop "nimSubInt"
|
||||
of CheckedMul: checkedBinaryop "nimMulInt"
|
||||
of CheckedDiv: checkedBinaryop "nimDivInt"
|
||||
of CheckedMod: checkedBinaryop "nimModInt"
|
||||
of Add: triop " + "
|
||||
of Sub: triop " - "
|
||||
of Mul: triop " * "
|
||||
of Div: triop " / "
|
||||
of Mod: triop " % "
|
||||
of BitShl: triop " << "
|
||||
of BitShr: triop " >> "
|
||||
of BitAnd: triop " & "
|
||||
of BitOr: triop " | "
|
||||
of BitXor: triop " ^ "
|
||||
of BitNot: binaryop " ~ "
|
||||
of BoolNot: binaryop " !"
|
||||
of Eq: cmpop " == "
|
||||
of Le: cmpop " <= "
|
||||
of Lt: cmpop " < "
|
||||
of Cast: binaryop ""
|
||||
of NumberConv: genNumberConv c, t, n
|
||||
of CheckedObjConv: binaryop ""
|
||||
of ObjConv: binaryop ""
|
||||
of Emit: raiseAssert "cannot interpret: Emit"
|
||||
of ProcDecl: genProcDecl c, t, n, false
|
||||
of ForeignProcDecl: genProcDecl c, t, n, true
|
||||
of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc:
|
||||
c.add "cannot interpret: " & $t[n].kind
|
||||
|
||||
const
|
||||
Prelude = """
|
||||
/* GENERATED CODE. DO NOT EDIT. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define NB8 bool
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
|
||||
// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>`
|
||||
#define NB8 _Bool
|
||||
#else
|
||||
typedef unsigned char NB8; // best effort
|
||||
#endif
|
||||
|
||||
typedef unsigned char NC8;
|
||||
|
||||
typedef float NF32;
|
||||
typedef double NF64;
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
typedef signed char NI8;
|
||||
typedef signed short int NI16;
|
||||
typedef signed int NI32;
|
||||
typedef __int64 NI64;
|
||||
/* XXX: Float128? */
|
||||
typedef unsigned char NU8;
|
||||
typedef unsigned short int NU16;
|
||||
typedef unsigned int NU32;
|
||||
typedef unsigned __int64 NU64;
|
||||
#elif defined(HAVE_STDINT_H)
|
||||
#ifndef USE_NIM_NAMESPACE
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
typedef int8_t NI8;
|
||||
typedef int16_t NI16;
|
||||
typedef int32_t NI32;
|
||||
typedef int64_t NI64;
|
||||
typedef uint8_t NU8;
|
||||
typedef uint16_t NU16;
|
||||
typedef uint32_t NU32;
|
||||
typedef uint64_t NU64;
|
||||
#elif defined(HAVE_CSTDINT)
|
||||
#ifndef USE_NIM_NAMESPACE
|
||||
# include <cstdint>
|
||||
#endif
|
||||
typedef std::int8_t NI8;
|
||||
typedef std::int16_t NI16;
|
||||
typedef std::int32_t NI32;
|
||||
typedef std::int64_t NI64;
|
||||
typedef std::uint8_t NU8;
|
||||
typedef std::uint16_t NU16;
|
||||
typedef std::uint32_t NU32;
|
||||
typedef std::uint64_t NU64;
|
||||
#else
|
||||
/* Unknown compiler/version, do our best */
|
||||
#ifdef __INT8_TYPE__
|
||||
typedef __INT8_TYPE__ NI8;
|
||||
#else
|
||||
typedef signed char NI8;
|
||||
#endif
|
||||
#ifdef __INT16_TYPE__
|
||||
typedef __INT16_TYPE__ NI16;
|
||||
#else
|
||||
typedef signed short int NI16;
|
||||
#endif
|
||||
#ifdef __INT32_TYPE__
|
||||
typedef __INT32_TYPE__ NI32;
|
||||
#else
|
||||
typedef signed int NI32;
|
||||
#endif
|
||||
#ifdef __INT64_TYPE__
|
||||
typedef __INT64_TYPE__ NI64;
|
||||
#else
|
||||
typedef long long int NI64;
|
||||
#endif
|
||||
/* XXX: Float128? */
|
||||
#ifdef __UINT8_TYPE__
|
||||
typedef __UINT8_TYPE__ NU8;
|
||||
#else
|
||||
typedef unsigned char NU8;
|
||||
#endif
|
||||
#ifdef __UINT16_TYPE__
|
||||
typedef __UINT16_TYPE__ NU16;
|
||||
#else
|
||||
typedef unsigned short int NU16;
|
||||
#endif
|
||||
#ifdef __UINT32_TYPE__
|
||||
typedef __UINT32_TYPE__ NU32;
|
||||
#else
|
||||
typedef unsigned int NU32;
|
||||
#endif
|
||||
#ifdef __UINT64_TYPE__
|
||||
typedef __UINT64_TYPE__ NU64;
|
||||
#else
|
||||
typedef unsigned long long int NU64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NIM_INTBITS
|
||||
# if NIM_INTBITS == 64
|
||||
typedef NI64 NI;
|
||||
typedef NU64 NU;
|
||||
# elif NIM_INTBITS == 32
|
||||
typedef NI32 NI;
|
||||
typedef NU32 NU;
|
||||
# elif NIM_INTBITS == 16
|
||||
typedef NI16 NI;
|
||||
typedef NU16 NU;
|
||||
# elif NIM_INTBITS == 8
|
||||
typedef NI8 NI;
|
||||
typedef NU8 NU;
|
||||
# else
|
||||
# error "invalid bit width for int"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
|
||||
|
||||
#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res})
|
||||
#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res})
|
||||
#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res})
|
||||
|
||||
#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res})
|
||||
#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res})
|
||||
#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res})
|
||||
|
||||
#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x})
|
||||
#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x})
|
||||
|
||||
"""
|
||||
|
||||
proc traverseCode(c: var GeneratedCode) =
|
||||
const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal,
|
||||
ProcDecl, ForeignDecl, ForeignProcDecl}
|
||||
var i = NodePos(0)
|
||||
while i.int < c.m.code.len:
|
||||
let oldLen = c.code.len
|
||||
let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC
|
||||
|
||||
gen c, c.m.code, NodePos(i)
|
||||
next c.m.code, i
|
||||
|
||||
if moveToInitSection:
|
||||
for i in oldLen ..< c.code.len:
|
||||
c.init.add c.code[i]
|
||||
setLen c.code, oldLen
|
||||
|
||||
proc generateCode*(inp, outp: string) =
|
||||
var c = initGeneratedCode(load(inp))
|
||||
|
||||
var co = TypeOrder()
|
||||
traverseTypes(c.m.types, c.m.lit, co)
|
||||
|
||||
generateTypes(c, c.m.types, c.m.lit, co)
|
||||
let typeDecls = move c.code
|
||||
|
||||
traverseCode c
|
||||
var f = CppFile(f: open(outp, fmWrite))
|
||||
f.write "#define NIM_INTBITS " & $c.m.intbits & "\n"
|
||||
f.write Prelude
|
||||
writeTokenSeq f, c.includes, c
|
||||
writeTokenSeq f, typeDecls, c
|
||||
writeTokenSeq f, c.data, c
|
||||
writeTokenSeq f, c.protos, c
|
||||
writeTokenSeq f, c.code, c
|
||||
if c.init.len > 0:
|
||||
f.write "void __attribute__((constructor)) init(void) {"
|
||||
writeTokenSeq f, c.init, c
|
||||
f.write "}\n\n"
|
||||
f.f.close
|
||||
105
compiler/nir/nir.nim
Normal file
105
compiler/nir/nir.nim
Normal file
@@ -0,0 +1,105 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
|
||||
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
|
||||
|
||||
from std/os import addFileExt, `/`, createDir
|
||||
|
||||
import std / assertions
|
||||
import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos]
|
||||
import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm
|
||||
|
||||
import ".." / ic / [rodfiles, bitabs]
|
||||
|
||||
type
|
||||
PCtx* = ref object of TPassContext
|
||||
m: ModuleCon
|
||||
c: ProcCon
|
||||
oldErrorCount: int
|
||||
bytecode: Bytecode
|
||||
|
||||
proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx =
|
||||
var lit = Literals()
|
||||
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
|
||||
var m = initModuleCon(g, g.config, idgen, module, nirm)
|
||||
m.noModularity = true
|
||||
PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm))
|
||||
|
||||
proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) =
|
||||
#c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm)
|
||||
#c.m.noModularity = true
|
||||
c.c = initProcCon(c.m, nil, c.m.graph.config)
|
||||
c.idgen = idgen
|
||||
|
||||
proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
|
||||
if graph.repl.isNil:
|
||||
graph.repl = newCtx(module, graph, idgen)
|
||||
#registerAdditionalOps(PCtx graph.repl)
|
||||
else:
|
||||
refresh(PCtx graph.repl, module, idgen)
|
||||
|
||||
proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
setupGlobalCtx(module, graph, idgen)
|
||||
result = PCtx graph.repl
|
||||
|
||||
proc evalStmt(c: PCtx; n: PNode) =
|
||||
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
|
||||
let pc = genStmt(c.c, n)
|
||||
#var res = ""
|
||||
#toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res
|
||||
#res.add "\n--------------------------\n"
|
||||
#toString res, c.m.types.g
|
||||
if pc.int < c.m.nirm.code.len:
|
||||
c.bytecode.interactive = c.m.graph.interactive
|
||||
execCode c.bytecode, c.m.nirm.code, pc
|
||||
#echo res
|
||||
|
||||
proc runCode*(c: PPassContext; n: PNode): PNode =
|
||||
let c = PCtx(c)
|
||||
# don't eval errornous code:
|
||||
if c.oldErrorCount == c.m.graph.config.errorCounter:
|
||||
evalStmt(c, n)
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
result = n
|
||||
c.oldErrorCount = c.m.graph.config.errorCounter
|
||||
|
||||
type
|
||||
NirPassContext* = ref object of TPassContext
|
||||
m: ModuleCon
|
||||
c: ProcCon
|
||||
|
||||
proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
|
||||
var lit = Literals()
|
||||
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
|
||||
let m = initModuleCon(g, g.config, idgen, module, nirm)
|
||||
NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen)
|
||||
|
||||
proc gen(c: NirPassContext; n: PNode) =
|
||||
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
|
||||
let pc = genStmt(c.c, n)
|
||||
|
||||
proc nirBackend*(c: PPassContext; n: PNode): PNode =
|
||||
gen(NirPassContext(c), n)
|
||||
result = n
|
||||
|
||||
proc closeNirBackend*(c: PPassContext; finalNode: PNode) =
|
||||
discard nirBackend(c, finalNode)
|
||||
|
||||
let c = NirPassContext(c)
|
||||
let nimcache = getNimcacheDir(c.c.config).string
|
||||
createDir nimcache
|
||||
let outp = nimcache / c.m.module.name.s.addFileExt("nir")
|
||||
#c.m.nirm.code = move c.c.code
|
||||
try:
|
||||
store c.m.nirm[], outp
|
||||
echo "created: ", outp
|
||||
except IOError:
|
||||
rawMessage(c.c.config, errFatal, "serialization failed: " & outp)
|
||||
52
compiler/nir/nirc.nim
Normal file
52
compiler/nir/nirc.nim
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Nir Compiler.
|
||||
|
||||
import ".." / ic / [bitabs, rodfiles]
|
||||
import nirinsts, nirtypes, nirlineinfos, nirfiles, cir
|
||||
|
||||
proc view(filename: string) =
|
||||
let m = load(filename)
|
||||
var res = ""
|
||||
allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res
|
||||
res.add "\n# TYPES\n"
|
||||
nirtypes.toString res, m.types
|
||||
echo res
|
||||
|
||||
import std / [syncio, parseopt]
|
||||
|
||||
proc writeHelp =
|
||||
echo """Usage: nirc view|c <file.nir>"""
|
||||
quit 0
|
||||
|
||||
proc main =
|
||||
var inp = ""
|
||||
var cmd = ""
|
||||
for kind, key, val in getopt():
|
||||
case kind
|
||||
of cmdArgument:
|
||||
if cmd.len == 0: cmd = key
|
||||
elif inp.len == 0: inp = key
|
||||
else: quit "Error: too many arguments"
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case key
|
||||
of "help", "h": writeHelp()
|
||||
of "version", "v": stdout.write "1.0\n"
|
||||
of cmdEnd: discard
|
||||
if inp.len == 0:
|
||||
quit "Error: no input file specified"
|
||||
case cmd
|
||||
of "", "view":
|
||||
view inp
|
||||
of "c":
|
||||
let outp = inp & ".c"
|
||||
cir.generateCode inp, outp
|
||||
|
||||
main()
|
||||
83
compiler/nir/nirfiles.nim
Normal file
83
compiler/nir/nirfiles.nim
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ".." / ic / [bitabs, rodfiles]
|
||||
import nirinsts, nirtypes, nirlineinfos
|
||||
|
||||
type
|
||||
NirModule* = object
|
||||
code*: Tree
|
||||
man*: LineInfoManager
|
||||
types*: TypeGraph
|
||||
lit*: Literals
|
||||
namespace*: LitId
|
||||
intbits*: uint32
|
||||
symnames*: SymNames
|
||||
|
||||
proc load*(filename: string): NirModule =
|
||||
let lit = Literals()
|
||||
result = NirModule(lit: lit, types: initTypeGraph(lit))
|
||||
var r = rodfiles.open(filename)
|
||||
try:
|
||||
r.loadHeader(nirCookie)
|
||||
r.loadSection stringsSection
|
||||
r.load result.lit.strings
|
||||
|
||||
r.loadSection numbersSection
|
||||
r.load result.lit.numbers
|
||||
|
||||
r.loadSection bodiesSection
|
||||
r.load result.code
|
||||
|
||||
r.loadSection typesSection
|
||||
r.load result.types
|
||||
|
||||
r.loadSection sideChannelSection
|
||||
r.load result.man
|
||||
|
||||
r.loadSection namespaceSection
|
||||
r.loadPrim result.namespace
|
||||
r.loadPrim result.intbits
|
||||
|
||||
r.loadSection symnamesSection
|
||||
r.load result.symnames
|
||||
|
||||
finally:
|
||||
r.close()
|
||||
|
||||
proc store*(m: NirModule; outp: string) =
|
||||
var r = rodfiles.create(outp)
|
||||
try:
|
||||
r.storeHeader(nirCookie)
|
||||
r.storeSection stringsSection
|
||||
r.store m.lit.strings
|
||||
|
||||
r.storeSection numbersSection
|
||||
r.store m.lit.numbers
|
||||
|
||||
r.storeSection bodiesSection
|
||||
r.store m.code
|
||||
|
||||
r.storeSection typesSection
|
||||
r.store m.types
|
||||
|
||||
r.storeSection sideChannelSection
|
||||
r.store m.man
|
||||
|
||||
r.storeSection namespaceSection
|
||||
r.storePrim m.namespace
|
||||
r.storePrim m.intbits
|
||||
|
||||
r.storeSection symnamesSection
|
||||
r.store m.symnames
|
||||
|
||||
finally:
|
||||
r.close()
|
||||
if r.err != ok:
|
||||
raise newException(IOError, "could store into: " & outp)
|
||||
582
compiler/nir/nirinsts.nim
Normal file
582
compiler/nir/nirinsts.nim
Normal file
@@ -0,0 +1,582 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## NIR instructions. Somewhat inspired by LLVM's instructions.
|
||||
|
||||
import std / [assertions, hashes]
|
||||
import .. / ic / [bitabs, rodfiles]
|
||||
import nirlineinfos, nirtypes
|
||||
|
||||
const
|
||||
NirVersion = 1
|
||||
nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'),
|
||||
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)]
|
||||
|
||||
type
|
||||
SymId* = distinct int
|
||||
|
||||
proc `$`*(s: SymId): string {.borrow.}
|
||||
proc hash*(s: SymId): Hash {.borrow.}
|
||||
proc `==`*(a, b: SymId): bool {.borrow.}
|
||||
|
||||
type
|
||||
Opcode* = enum
|
||||
Nop,
|
||||
ImmediateVal,
|
||||
IntVal,
|
||||
StrVal,
|
||||
SymDef,
|
||||
SymUse,
|
||||
Typed, # with type ID
|
||||
PragmaId, # with Pragma ID, possible values: see PragmaKey enum
|
||||
NilVal,
|
||||
Label,
|
||||
Goto,
|
||||
CheckedGoto,
|
||||
LoopLabel,
|
||||
GotoLoop, # last atom
|
||||
|
||||
ModuleSymUse, # `"module".x`
|
||||
|
||||
ArrayConstr,
|
||||
ObjConstr,
|
||||
Ret,
|
||||
Yld,
|
||||
|
||||
Select,
|
||||
SelectPair, # ((values...), Label)
|
||||
SelectList, # (values...)
|
||||
SelectValue, # (value)
|
||||
SelectRange, # (valueA..valueB)
|
||||
ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst
|
||||
SummonGlobal,
|
||||
SummonThreadLocal,
|
||||
Summon, # x = Summon Typed <Type ID>; x begins to live
|
||||
SummonResult,
|
||||
SummonParam,
|
||||
SummonConst,
|
||||
Kill, # `Kill x`: scope end for `x`
|
||||
|
||||
AddrOf,
|
||||
ArrayAt, # a[i]
|
||||
DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
|
||||
FieldAt, # obj.field
|
||||
DerefFieldAt, # obj[].field
|
||||
|
||||
Load, # a[]
|
||||
Store, # a[] = b
|
||||
Asgn, # a = b
|
||||
SetExc,
|
||||
TestExc,
|
||||
|
||||
CheckedRange,
|
||||
CheckedIndex,
|
||||
|
||||
Call,
|
||||
IndirectCall,
|
||||
CheckedCall, # call that can raise
|
||||
CheckedIndirectCall, # call that can raise
|
||||
CheckedAdd, # with overflow checking etc.
|
||||
CheckedSub,
|
||||
CheckedMul,
|
||||
CheckedDiv,
|
||||
CheckedMod,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
BitShl,
|
||||
BitShr,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
BitNot,
|
||||
BoolNot,
|
||||
Eq,
|
||||
Le,
|
||||
Lt,
|
||||
Cast,
|
||||
NumberConv,
|
||||
CheckedObjConv,
|
||||
ObjConv,
|
||||
TestOf,
|
||||
Emit,
|
||||
ProcDecl,
|
||||
ForeignProcDecl,
|
||||
PragmaPair
|
||||
|
||||
type
|
||||
PragmaKey* = enum
|
||||
FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall,
|
||||
CoreName,
|
||||
ExternName,
|
||||
HeaderImport,
|
||||
DllImport,
|
||||
DllExport,
|
||||
ObjExport
|
||||
|
||||
const
|
||||
LastAtomicValue = GotoLoop
|
||||
|
||||
OpcodeBits = 8'u32
|
||||
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
|
||||
|
||||
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
|
||||
|
||||
ValueProducing* = {
|
||||
ImmediateVal,
|
||||
IntVal,
|
||||
StrVal,
|
||||
SymUse,
|
||||
NilVal,
|
||||
ModuleSymUse,
|
||||
ArrayConstr,
|
||||
ObjConstr,
|
||||
CheckedAdd,
|
||||
CheckedSub,
|
||||
CheckedMul,
|
||||
CheckedDiv,
|
||||
CheckedMod,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
BitShl,
|
||||
BitShr,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
BitNot,
|
||||
BoolNot,
|
||||
Eq,
|
||||
Le,
|
||||
Lt,
|
||||
Cast,
|
||||
NumberConv,
|
||||
CheckedObjConv,
|
||||
ObjConv,
|
||||
AddrOf,
|
||||
Load,
|
||||
ArrayAt,
|
||||
DerefArrayAt,
|
||||
FieldAt,
|
||||
DerefFieldAt,
|
||||
TestOf
|
||||
}
|
||||
|
||||
type
|
||||
Instr* = object # 8 bytes
|
||||
x: uint32
|
||||
info*: PackedLineInfo
|
||||
|
||||
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
|
||||
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
|
||||
|
||||
template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits)
|
||||
|
||||
template toX(k: Opcode; operand: uint32): uint32 =
|
||||
uint32(k) or (operand shl OpcodeBits)
|
||||
|
||||
template toX(k: Opcode; operand: LitId): uint32 =
|
||||
uint32(k) or (operand.uint32 shl OpcodeBits)
|
||||
|
||||
type
|
||||
Tree* = object
|
||||
nodes: seq[Instr]
|
||||
|
||||
Values* = object
|
||||
numbers: BiTable[int64]
|
||||
strings: BiTable[string]
|
||||
|
||||
type
|
||||
PatchPos* = distinct int
|
||||
NodePos* = distinct int
|
||||
|
||||
const
|
||||
InvalidPatchPos* = PatchPos(-1)
|
||||
|
||||
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
|
||||
|
||||
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
|
||||
result = PatchPos tree.nodes.len
|
||||
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
|
||||
|
||||
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
|
||||
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
|
||||
|
||||
proc patch*(tree: var Tree; pos: PatchPos) =
|
||||
let pos = pos.int
|
||||
let k = tree.nodes[pos].kind
|
||||
assert k > LastAtomicValue
|
||||
let distance = int32(tree.nodes.len - pos)
|
||||
assert distance > 0
|
||||
tree.nodes[pos].x = toX(k, cast[uint32](distance))
|
||||
|
||||
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
|
||||
let pos = prepare(tree, info, kind)
|
||||
body
|
||||
patch(tree, pos)
|
||||
|
||||
template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
|
||||
let pos = prepare(tree, info, kind)
|
||||
tree.addTyped info, typ
|
||||
body
|
||||
patch(tree, pos)
|
||||
|
||||
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
|
||||
|
||||
template rawSpan(n: Instr): int = int(operand(n))
|
||||
|
||||
proc nextChild(tree: Tree; pos: var int) {.inline.} =
|
||||
if tree.nodes[pos].kind > LastAtomicValue:
|
||||
assert tree.nodes[pos].operand > 0'u32
|
||||
inc pos, tree.nodes[pos].rawSpan
|
||||
else:
|
||||
inc pos
|
||||
|
||||
proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
|
||||
|
||||
template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
|
||||
|
||||
template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
|
||||
|
||||
iterator sons*(tree: Tree; n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > LastAtomicValue
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > LastAtomicValue
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
nextChild tree, pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > LastAtomicValue
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
for i in 1..toSkip:
|
||||
nextChild tree, pos
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
|
||||
|
||||
iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos =
|
||||
var pos = n.int
|
||||
assert tree[parent].kind > LastAtomicValue
|
||||
let last = parent.int + tree[parent].rawSpan
|
||||
while pos < last:
|
||||
yield NodePos pos
|
||||
nextChild tree, pos
|
||||
|
||||
proc span(tree: Tree; pos: int): int {.inline.} =
|
||||
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
|
||||
|
||||
proc copyTree*(dest: var Tree; src: Tree) =
|
||||
let pos = 0
|
||||
let L = span(src, pos)
|
||||
let d = dest.nodes.len
|
||||
dest.nodes.setLen(d + L)
|
||||
assert L > 0
|
||||
for i in 0..<L:
|
||||
dest.nodes[d+i] = src.nodes[pos+i]
|
||||
|
||||
proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
result = (NodePos a, NodePos b)
|
||||
|
||||
proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) {.inline.} =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
let c = b + span(tree, b)
|
||||
result = (NodePos a, NodePos b, NodePos c)
|
||||
|
||||
proc sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
let c = b + span(tree, b)
|
||||
let d = c + span(tree, c)
|
||||
result = (NodePos a, NodePos b, NodePos c, NodePos d)
|
||||
|
||||
proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
let c = b + span(tree, b)
|
||||
let d = c + span(tree, c)
|
||||
let e = d + span(tree, d)
|
||||
result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)
|
||||
|
||||
proc typeId*(ins: Instr): TypeId {.inline.} =
|
||||
assert ins.kind == Typed
|
||||
result = TypeId(ins.operand)
|
||||
|
||||
proc symId*(ins: Instr): SymId {.inline.} =
|
||||
assert ins.kind in {SymUse, SymDef}
|
||||
result = SymId(ins.operand)
|
||||
|
||||
proc immediateVal*(ins: Instr): int {.inline.} =
|
||||
assert ins.kind == ImmediateVal
|
||||
result = cast[int](ins.operand)
|
||||
|
||||
proc litId*(ins: Instr): LitId {.inline.} =
|
||||
assert ins.kind in {StrVal, IntVal}
|
||||
result = LitId(ins.operand)
|
||||
|
||||
|
||||
type
|
||||
LabelId* = distinct int
|
||||
|
||||
proc `==`*(a, b: LabelId): bool {.borrow.}
|
||||
proc hash*(a: LabelId): Hash {.borrow.}
|
||||
|
||||
proc label*(ins: Instr): LabelId {.inline.} =
|
||||
assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
|
||||
result = LabelId(ins.operand)
|
||||
|
||||
proc newLabel*(labelGen: var int): LabelId {.inline.} =
|
||||
result = LabelId labelGen
|
||||
inc labelGen
|
||||
|
||||
proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} =
|
||||
result = LabelId labelGen
|
||||
inc labelGen, n
|
||||
|
||||
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
|
||||
assert k in {Label, LoopLabel}
|
||||
result = LabelId labelGen
|
||||
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
|
||||
inc labelGen
|
||||
|
||||
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
|
||||
assert k in {Goto, GotoLoop, CheckedGoto}
|
||||
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
|
||||
|
||||
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
|
||||
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
|
||||
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
|
||||
|
||||
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
|
||||
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
|
||||
|
||||
proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
|
||||
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
|
||||
|
||||
proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} =
|
||||
t.nodes.add Instr(x: toX(Nop, 0'u32), info: info)
|
||||
|
||||
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
|
||||
assert typ.int >= 0
|
||||
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
|
||||
|
||||
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} =
|
||||
assert typ.int >= 0
|
||||
assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult}
|
||||
let x = prepare(t, info, opc)
|
||||
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
|
||||
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
|
||||
patch t, x
|
||||
|
||||
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
|
||||
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
|
||||
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
|
||||
|
||||
proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) =
|
||||
t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info)
|
||||
|
||||
proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
|
||||
buildTyped t, info, NumberConv, typ:
|
||||
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
|
||||
|
||||
proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
|
||||
buildTyped t, info, NumberConv, Bool8Id:
|
||||
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
|
||||
|
||||
proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
|
||||
t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
|
||||
|
||||
proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) =
|
||||
t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info)
|
||||
|
||||
proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) =
|
||||
buildTyped t, info, NumberConv, typ:
|
||||
t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info)
|
||||
|
||||
proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes
|
||||
proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes
|
||||
|
||||
proc escapeToNimLit*(s: string; result: var string) =
|
||||
result.add '"'
|
||||
for c in items s:
|
||||
if c < ' ' or int(c) >= 128:
|
||||
result.add '\\'
|
||||
result.addInt int(c)
|
||||
elif c == '\\':
|
||||
result.add r"\\"
|
||||
elif c == '\n':
|
||||
result.add r"\n"
|
||||
elif c == '\r':
|
||||
result.add r"\r"
|
||||
elif c == '\t':
|
||||
result.add r"\t"
|
||||
else:
|
||||
result.add c
|
||||
result.add '"'
|
||||
|
||||
type
|
||||
SymNames* = object
|
||||
s: seq[LitId]
|
||||
|
||||
proc `[]=`*(t: var SymNames; key: SymId; val: LitId) =
|
||||
let k = int(key)
|
||||
if k >= t.s.len: t.s.setLen k+1
|
||||
t.s[k] = val
|
||||
|
||||
proc `[]`*(t: SymNames; key: SymId): LitId =
|
||||
let k = int(key)
|
||||
if k < t.s.len: result = t.s[k]
|
||||
else: result = LitId(0)
|
||||
|
||||
template localName(s: SymId): string =
|
||||
let name = names[s]
|
||||
if name != LitId(0):
|
||||
strings[name]
|
||||
else:
|
||||
$s.int
|
||||
|
||||
proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s)
|
||||
proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s)
|
||||
|
||||
proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64];
|
||||
names: SymNames;
|
||||
r: var string; nesting = 0) =
|
||||
if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
|
||||
r.add ' '
|
||||
|
||||
case t[pos].kind
|
||||
of Nop: r.add "Nop"
|
||||
of ImmediateVal:
|
||||
r.add $t[pos].operand
|
||||
of IntVal:
|
||||
r.add "IntVal "
|
||||
r.add $integers[LitId t[pos].operand]
|
||||
of StrVal:
|
||||
escapeToNimLit(strings[LitId t[pos].operand], r)
|
||||
of SymDef:
|
||||
r.add "SymDef "
|
||||
r.add localName(SymId t[pos].operand)
|
||||
of SymUse:
|
||||
r.add "SymUse "
|
||||
r.add localName(SymId t[pos].operand)
|
||||
of PragmaId:
|
||||
r.add $cast[PragmaKey](t[pos].operand)
|
||||
of Typed:
|
||||
r.add "T<"
|
||||
r.add $t[pos].operand
|
||||
r.add ">"
|
||||
of NilVal:
|
||||
r.add "NilVal"
|
||||
of Label:
|
||||
# undo the nesting:
|
||||
var spaces = r.len-1
|
||||
while spaces >= 0 and r[spaces] == ' ': dec spaces
|
||||
r.setLen spaces+1
|
||||
r.add "\n L"
|
||||
r.add $t[pos].operand
|
||||
of Goto, CheckedGoto, LoopLabel, GotoLoop:
|
||||
r.add $t[pos].kind
|
||||
r.add " L"
|
||||
r.add $t[pos].operand
|
||||
else:
|
||||
r.add $t[pos].kind
|
||||
r.add "{\n"
|
||||
for i in 0..<(nesting+1)*2: r.add ' '
|
||||
for p in sons(t, pos):
|
||||
toString t, p, strings, integers, names, r, nesting+1
|
||||
r.add "\n"
|
||||
for i in 0..<nesting*2: r.add ' '
|
||||
r.add "}"
|
||||
|
||||
proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64];
|
||||
names: SymNames;
|
||||
r: var string) =
|
||||
var i = 0
|
||||
while i < t.len:
|
||||
toString t, NodePos(i), strings, integers, names, r
|
||||
nextChild t, i
|
||||
|
||||
type
|
||||
Value* = distinct Tree
|
||||
|
||||
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
|
||||
assert k in ValueProducing - ValueProducingAtoms
|
||||
result = prepare(Tree(dest), info, k)
|
||||
|
||||
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
|
||||
patch(Tree(dest), pos)
|
||||
|
||||
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
|
||||
result = Value(Tree())
|
||||
Tree(result).addSymUse info, s
|
||||
|
||||
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
|
||||
|
||||
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
|
||||
|
||||
proc extractTemp*(v: Value): SymId =
|
||||
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
|
||||
result = SymId(Tree(v)[NodePos 0].operand)
|
||||
else:
|
||||
result = SymId(-1)
|
||||
|
||||
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
|
||||
|
||||
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
|
||||
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
|
||||
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
|
||||
|
||||
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
|
||||
let pos = prepare(Tree(tree), info, kind)
|
||||
body
|
||||
patch(tree, pos)
|
||||
|
||||
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
|
||||
addTyped(Tree(t), info, typ)
|
||||
|
||||
template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
|
||||
let pos = prepare(tree, info, kind)
|
||||
tree.addTyped info, typ
|
||||
body
|
||||
patch(tree, pos)
|
||||
|
||||
proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
|
||||
addStrVal(Tree(t), strings, info, s)
|
||||
|
||||
proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) =
|
||||
addNilVal Tree(t), info, typ
|
||||
|
||||
proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
|
||||
addIntVal Tree(t), integers, info, typ, x
|
||||
84
compiler/nir/nirlineinfos.nim
Normal file
84
compiler/nir/nirlineinfos.nim
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# For the line information we use 32 bits. They are used as follows:
|
||||
# Bit 0 (AsideBit): If we have inline line information or not. If not, the
|
||||
# remaining 31 bits are used as an index into a seq[(LitId, int, int)].
|
||||
#
|
||||
# We use 10 bits for the "file ID", this means a program can consist of as much
|
||||
# as 1024 different files. (If it uses more files than that, the overflow bit
|
||||
# would be set.)
|
||||
# This means we have 21 bits left to encode the (line, col) pair. We use 7 bits for the column
|
||||
# so 128 is the limit and 14 bits for the line number.
|
||||
# The packed representation supports files with up to 16384 lines.
|
||||
# Keep in mind that whenever any limit is reached the AsideBit is set and the real line
|
||||
# information is kept in a side channel.
|
||||
|
||||
import std / assertions
|
||||
|
||||
const
|
||||
AsideBit = 1
|
||||
FileBits = 10
|
||||
LineBits = 14
|
||||
ColBits = 7
|
||||
FileMax = (1 shl FileBits) - 1
|
||||
LineMax = (1 shl LineBits) - 1
|
||||
ColMax = (1 shl ColBits) - 1
|
||||
|
||||
static:
|
||||
assert AsideBit + FileBits + LineBits + ColBits == 32
|
||||
|
||||
import .. / ic / [bitabs, rodfiles] # for LitId
|
||||
|
||||
type
|
||||
PackedLineInfo* = distinct uint32
|
||||
|
||||
LineInfoManager* = object
|
||||
aside: seq[(LitId, int32, int32)]
|
||||
|
||||
const
|
||||
NoLineInfo* = PackedLineInfo(0'u32)
|
||||
|
||||
proc pack*(m: var LineInfoManager; file: LitId; line, col: int32): PackedLineInfo =
|
||||
if file.uint32 <= FileMax.uint32 and line <= LineMax and col <= ColMax:
|
||||
let col = if col < 0'i32: 0'u32 else: col.uint32
|
||||
let line = if line < 0'i32: 0'u32 else: line.uint32
|
||||
# use inline representation:
|
||||
result = PackedLineInfo((file.uint32 shl 1'u32) or (line shl uint32(AsideBit + FileBits)) or
|
||||
(col shl uint32(AsideBit + FileBits + LineBits)))
|
||||
else:
|
||||
result = PackedLineInfo((m.aside.len shl 1) or AsideBit)
|
||||
m.aside.add (file, line, col)
|
||||
|
||||
proc unpack*(m: LineInfoManager; i: PackedLineInfo): (LitId, int32, int32) =
|
||||
let i = i.uint32
|
||||
if (i and 1'u32) == 0'u32:
|
||||
# inline representation:
|
||||
result = (LitId((i shr 1'u32) and FileMax.uint32),
|
||||
int32((i shr uint32(AsideBit + FileBits)) and LineMax.uint32),
|
||||
int32((i shr uint32(AsideBit + FileBits + LineBits)) and ColMax.uint32))
|
||||
else:
|
||||
result = m.aside[int(i shr 1'u32)]
|
||||
|
||||
proc getFileId*(m: LineInfoManager; i: PackedLineInfo): LitId =
|
||||
result = unpack(m, i)[0]
|
||||
|
||||
proc store*(r: var RodFile; m: LineInfoManager) = storeSeq(r, m.aside)
|
||||
proc load*(r: var RodFile; m: var LineInfoManager) = loadSeq(r, m.aside)
|
||||
|
||||
when isMainModule:
|
||||
var m = LineInfoManager(aside: @[])
|
||||
for i in 0'i32..<16388'i32:
|
||||
for col in 0'i32..<100'i32:
|
||||
let packed = pack(m, LitId(1023), i, col)
|
||||
let u = unpack(m, packed)
|
||||
assert u[0] == LitId(1023)
|
||||
assert u[1] == i
|
||||
assert u[2] == col
|
||||
echo m.aside.len
|
||||
104
compiler/nir/nirslots.nim
Normal file
104
compiler/nir/nirslots.nim
Normal file
@@ -0,0 +1,104 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Management of slots. Similar to "register allocation"
|
||||
## in lower level languages.
|
||||
|
||||
import std / [assertions, tables]
|
||||
import nirtypes, nirinsts
|
||||
|
||||
type
|
||||
SlotManagerFlag* = enum
|
||||
ReuseTemps,
|
||||
ReuseVars
|
||||
SlotKind* = enum
|
||||
Temp, Perm
|
||||
SlotManager* = object # "register allocator"
|
||||
live: Table[SymId, (SlotKind, TypeId)]
|
||||
dead: Table[TypeId, seq[SymId]]
|
||||
flags: set[SlotManagerFlag]
|
||||
inScope: seq[SymId]
|
||||
|
||||
proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} =
|
||||
SlotManager(flags: flags)
|
||||
|
||||
proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind;
|
||||
symIdgen: var int32): SymId {.inline.} =
|
||||
if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
|
||||
result = m.dead[t].pop()
|
||||
else:
|
||||
inc symIdgen
|
||||
result = SymId(symIdgen)
|
||||
m.inScope.add result
|
||||
m.live[result] = (k, t)
|
||||
|
||||
proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
|
||||
result = allocRaw(m, t, ReuseTemps, Temp, symIdgen)
|
||||
|
||||
proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
|
||||
result = allocRaw(m, t, ReuseVars, Perm, symIdgen)
|
||||
|
||||
proc freeLoc*(m: var SlotManager; s: SymId) =
|
||||
let t = m.live.getOrDefault(s)
|
||||
assert t[1].int != 0
|
||||
m.live.del s
|
||||
m.dead.mgetOrPut(t[1], @[]).add s
|
||||
|
||||
proc freeTemp*(m: var SlotManager; s: SymId) =
|
||||
let t = m.live.getOrDefault(s)
|
||||
if t[1].int != 0 and t[0] == Temp:
|
||||
m.live.del s
|
||||
m.dead.mgetOrPut(t[1], @[]).add s
|
||||
|
||||
iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
|
||||
for k, v in pairs(m.live):
|
||||
yield (k, v[1])
|
||||
|
||||
proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1]
|
||||
|
||||
proc openScope*(m: var SlotManager) =
|
||||
m.inScope.add SymId(-1) # add marker
|
||||
|
||||
proc closeScope*(m: var SlotManager) =
|
||||
var i = m.inScope.len - 1
|
||||
while i >= 0:
|
||||
if m.inScope[i] == SymId(-1):
|
||||
m.inScope.setLen i
|
||||
break
|
||||
dec i
|
||||
|
||||
when isMainModule:
|
||||
var symIdgen: int32
|
||||
var m = initSlotManager({ReuseTemps})
|
||||
|
||||
var g = initTypeGraph(Literals())
|
||||
|
||||
let a = g.openType ArrayTy
|
||||
g.addBuiltinType Int8Id
|
||||
g.addArrayLen 5
|
||||
let finalArrayType = finishType(g, a)
|
||||
|
||||
let obj = g.openType ObjectDecl
|
||||
g.addName "MyType"
|
||||
|
||||
g.addField "p", finalArrayType, 0
|
||||
let objB = finishType(g, obj)
|
||||
|
||||
let x = m.allocTemp(objB, symIdgen)
|
||||
assert x.int == 0
|
||||
|
||||
let y = m.allocTemp(objB, symIdgen)
|
||||
assert y.int == 1
|
||||
|
||||
let z = m.allocTemp(Int8Id, symIdgen)
|
||||
assert z.int == 2
|
||||
|
||||
m.freeLoc y
|
||||
let y2 = m.allocTemp(objB, symIdgen)
|
||||
assert y2.int == 1
|
||||
475
compiler/nir/nirtypes.nim
Normal file
475
compiler/nir/nirtypes.nim
Normal file
@@ -0,0 +1,475 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Type system for NIR. Close to C's type system but without its quirks.
|
||||
|
||||
import std / [assertions, hashes]
|
||||
import .. / ic / [bitabs, rodfiles]
|
||||
|
||||
type
|
||||
NirTypeKind* = enum
|
||||
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
|
||||
IntVal, SizeVal, AlignVal, OffsetVal,
|
||||
AnnotationVal,
|
||||
ObjectTy,
|
||||
UnionTy,
|
||||
VarargsTy, # the `...` in a C prototype; also the last "atom"
|
||||
APtrTy, # pointer to aliasable memory
|
||||
UPtrTy, # pointer to unique/unaliasable memory
|
||||
AArrayPtrTy, # pointer to array of aliasable memory
|
||||
UArrayPtrTy, # pointer to array of unique/unaliasable memory
|
||||
ArrayTy,
|
||||
LastArrayTy, # array of unspecified size as a last field inside an object
|
||||
ProcTy,
|
||||
ObjectDecl,
|
||||
UnionDecl,
|
||||
FieldDecl
|
||||
|
||||
const
|
||||
TypeKindBits = 8'u32
|
||||
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
|
||||
|
||||
type
|
||||
TypeNode* = object # 4 bytes
|
||||
x: uint32
|
||||
|
||||
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
|
||||
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
|
||||
|
||||
proc integralBits*(n: TypeNode): int {.inline.} =
|
||||
# Number of bits in the IntTy, etc. Only valid for integral types.
|
||||
assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
|
||||
result = int(n.operand)
|
||||
|
||||
template toX(k: NirTypeKind; operand: uint32): uint32 =
|
||||
uint32(k) or (operand shl TypeKindBits)
|
||||
|
||||
template toX(k: NirTypeKind; operand: LitId): uint32 =
|
||||
uint32(k) or (operand.uint32 shl TypeKindBits)
|
||||
|
||||
type
|
||||
TypeId* = distinct int
|
||||
|
||||
proc `==`*(a, b: TypeId): bool {.borrow.}
|
||||
proc hash*(a: TypeId): Hash {.borrow.}
|
||||
|
||||
type
|
||||
Literals* = ref object
|
||||
strings*: BiTable[string]
|
||||
numbers*: BiTable[int64]
|
||||
|
||||
TypeGraph* = object
|
||||
nodes: seq[TypeNode]
|
||||
lit: Literals
|
||||
|
||||
const
|
||||
VoidId* = TypeId 0
|
||||
Bool8Id* = TypeId 1
|
||||
Char8Id* = TypeId 2
|
||||
Int8Id* = TypeId 3
|
||||
Int16Id* = TypeId 4
|
||||
Int32Id* = TypeId 5
|
||||
Int64Id* = TypeId 6
|
||||
UInt8Id* = TypeId 7
|
||||
UInt16Id* = TypeId 8
|
||||
UInt32Id* = TypeId 9
|
||||
UInt64Id* = TypeId 10
|
||||
Float32Id* = TypeId 11
|
||||
Float64Id* = TypeId 12
|
||||
VoidPtrId* = TypeId 13
|
||||
LastBuiltinId* = 13
|
||||
|
||||
proc initTypeGraph*(lit: Literals): TypeGraph =
|
||||
result = TypeGraph(nodes: @[
|
||||
TypeNode(x: toX(VoidTy, 0'u32)),
|
||||
TypeNode(x: toX(BoolTy, 8'u32)),
|
||||
TypeNode(x: toX(CharTy, 8'u32)),
|
||||
TypeNode(x: toX(IntTy, 8'u32)),
|
||||
TypeNode(x: toX(IntTy, 16'u32)),
|
||||
TypeNode(x: toX(IntTy, 32'u32)),
|
||||
TypeNode(x: toX(IntTy, 64'u32)),
|
||||
TypeNode(x: toX(UIntTy, 8'u32)),
|
||||
TypeNode(x: toX(UIntTy, 16'u32)),
|
||||
TypeNode(x: toX(UIntTy, 32'u32)),
|
||||
TypeNode(x: toX(UIntTy, 64'u32)),
|
||||
TypeNode(x: toX(FloatTy, 32'u32)),
|
||||
TypeNode(x: toX(FloatTy, 64'u32)),
|
||||
TypeNode(x: toX(APtrTy, 2'u32)),
|
||||
TypeNode(x: toX(VoidTy, 0'u32))
|
||||
], lit: lit)
|
||||
assert result.nodes.len == LastBuiltinId+2
|
||||
|
||||
type
|
||||
TypePatchPos* = distinct int
|
||||
|
||||
const
|
||||
InvalidTypePatchPos* = TypePatchPos(-1)
|
||||
LastAtomicValue = VarargsTy
|
||||
|
||||
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
|
||||
|
||||
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
|
||||
result = TypePatchPos tree.nodes.len
|
||||
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
|
||||
|
||||
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
|
||||
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
|
||||
|
||||
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
|
||||
let pos = pos.int
|
||||
let k = tree.nodes[pos].kind
|
||||
assert k > LastAtomicValue
|
||||
let distance = int32(tree.nodes.len - pos)
|
||||
assert distance > 0
|
||||
tree.nodes[pos].x = toX(k, cast[uint32](distance))
|
||||
|
||||
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
|
||||
|
||||
template rawSpan(n: TypeNode): int = int(operand(n))
|
||||
|
||||
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
|
||||
if tree.nodes[pos].kind > LastAtomicValue:
|
||||
assert tree.nodes[pos].operand > 0'u32
|
||||
inc pos, tree.nodes[pos].rawSpan
|
||||
else:
|
||||
inc pos
|
||||
|
||||
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind > LastAtomicValue
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
while pos < last:
|
||||
yield TypeId pos
|
||||
nextChild tree, pos
|
||||
|
||||
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
|
||||
|
||||
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
|
||||
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
|
||||
result = TypeId(n.int+1)
|
||||
|
||||
proc litId*(n: TypeNode): LitId {.inline.} =
|
||||
assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
|
||||
result = LitId(n.operand)
|
||||
|
||||
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
|
||||
|
||||
proc span(tree: TypeGraph; pos: int): int {.inline.} =
|
||||
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
|
||||
|
||||
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
result = (TypeId a, TypeId b)
|
||||
|
||||
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
|
||||
assert(not isAtom(tree, n.int))
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
let c = b + span(tree, b)
|
||||
result = (TypeId a, TypeId b, TypeId c)
|
||||
|
||||
proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
|
||||
assert tree[n].kind == ArrayTy
|
||||
let (_, _, c) = sons3(tree, n)
|
||||
result = c
|
||||
|
||||
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
|
||||
assert tree[n].kind == ArrayTy
|
||||
let (_, b) = sons2(tree, n)
|
||||
result = tree.lit.numbers[LitId tree[b].operand]
|
||||
|
||||
proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
|
||||
# Returns the positions of the return type + calling convention.
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind == ProcTy
|
||||
let a = n.int+1
|
||||
let b = a + span(tree, a)
|
||||
result = (TypeId b, TypeId a) # not a typo, order is reversed
|
||||
|
||||
iterator params*(tree: TypeGraph; n: TypeId): TypeId =
|
||||
var pos = n.int
|
||||
assert tree.nodes[pos].kind == ProcTy
|
||||
let last = pos + tree.nodes[pos].rawSpan
|
||||
inc pos
|
||||
nextChild tree, pos
|
||||
nextChild tree, pos
|
||||
while pos < last:
|
||||
yield TypeId pos
|
||||
nextChild tree, pos
|
||||
|
||||
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
|
||||
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
|
||||
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
|
||||
FieldDecl}
|
||||
result = prepare(tree, kind)
|
||||
|
||||
template typeInvariant(p: TypePatchPos) =
|
||||
when false:
|
||||
if tree[TypeId(p)].kind == FieldDecl:
|
||||
var k = 0
|
||||
for ch in sons(tree, TypeId(p)):
|
||||
inc k
|
||||
assert k > 2, "damn! " & $k
|
||||
|
||||
proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
|
||||
patch tree, p
|
||||
typeInvariant(p)
|
||||
|
||||
proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
|
||||
# Search for an existing instance of this type in
|
||||
# order to reduce memory consumption:
|
||||
patch tree, p
|
||||
typeInvariant(p)
|
||||
|
||||
let s = span(tree, p.int)
|
||||
var i = 0
|
||||
while i < p.int:
|
||||
if tree.nodes[i].x == tree.nodes[p.int].x:
|
||||
var isMatch = true
|
||||
for j in 1..<s:
|
||||
if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
|
||||
discard "still a match"
|
||||
else:
|
||||
isMatch = false
|
||||
break
|
||||
if isMatch:
|
||||
if p.int+s == tree.len:
|
||||
setLen tree.nodes, p.int
|
||||
return TypeId(i)
|
||||
nextChild tree, i
|
||||
result = TypeId(p)
|
||||
|
||||
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
|
||||
assert kind in {ObjectTy, UnionTy}
|
||||
let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
|
||||
for i in 0..<tree.len:
|
||||
if tree.nodes[i].x == content.x:
|
||||
return TypeId(i)
|
||||
result = TypeId tree.nodes.len
|
||||
tree.nodes.add content
|
||||
|
||||
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
|
||||
assert kind in {ObjectTy, UnionTy}
|
||||
tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
|
||||
|
||||
proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
|
||||
assert tree[t].kind in {ObjectTy, UnionTy}
|
||||
result = tree.lit.strings[LitId tree[t].operand]
|
||||
|
||||
proc addVarargs*(tree: var TypeGraph) =
|
||||
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
|
||||
|
||||
proc getFloat128Type*(tree: var TypeGraph): TypeId =
|
||||
result = TypeId tree.nodes.len
|
||||
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
|
||||
|
||||
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
|
||||
g.nodes.add g[id]
|
||||
|
||||
template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
|
||||
|
||||
proc addType*(g: var TypeGraph; t: TypeId) =
|
||||
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
|
||||
if g[t].kind in {ObjectDecl, UnionDecl}:
|
||||
assert g[t.firstSon].kind == NameVal
|
||||
let name = LitId g[t.firstSon].operand
|
||||
if g[t].kind == ObjectDecl:
|
||||
g.nodes.add TypeNode(x: toX(ObjectTy, name))
|
||||
else:
|
||||
g.nodes.add TypeNode(x: toX(UnionTy, name))
|
||||
else:
|
||||
let pos = t.int
|
||||
let L = span(g, pos)
|
||||
let d = g.nodes.len
|
||||
g.nodes.setLen(d + L)
|
||||
assert L > 0
|
||||
for i in 0..<L:
|
||||
g.nodes[d+i] = g.nodes[pos+i]
|
||||
|
||||
proc addArrayLen*(g: var TypeGraph; len: int64) =
|
||||
g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
|
||||
|
||||
proc addSize*(g: var TypeGraph; s: int64) =
|
||||
g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
|
||||
|
||||
proc addOffset*(g: var TypeGraph; offset: int64) =
|
||||
g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
|
||||
|
||||
proc addAlign*(g: var TypeGraph; a: int64) =
|
||||
g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
|
||||
|
||||
proc addName*(g: var TypeGraph; name: string) =
|
||||
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
|
||||
|
||||
proc addAnnotation*(g: var TypeGraph; name: string) =
|
||||
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
|
||||
|
||||
proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
|
||||
let f = g.openType FieldDecl
|
||||
g.addType typ
|
||||
g.addOffset offset
|
||||
g.addName name
|
||||
sealType(g, f)
|
||||
|
||||
proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
|
||||
let f = g.openType APtrTy
|
||||
g.addType t
|
||||
result = finishType(g, f)
|
||||
|
||||
proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
|
||||
let f = g.openType AArrayPtrTy
|
||||
g.addType t
|
||||
result = finishType(g, f)
|
||||
|
||||
proc store*(r: var RodFile; g: TypeGraph) =
|
||||
storeSeq r, g.nodes
|
||||
|
||||
proc load*(r: var RodFile; g: var TypeGraph) =
|
||||
loadSeq r, g.nodes
|
||||
|
||||
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
|
||||
case g[i].kind
|
||||
of VoidTy: dest.add "void"
|
||||
of IntTy:
|
||||
dest.add "i"
|
||||
dest.addInt g[i].operand
|
||||
of UIntTy:
|
||||
dest.add "u"
|
||||
dest.addInt g[i].operand
|
||||
of FloatTy:
|
||||
dest.add "f"
|
||||
dest.addInt g[i].operand
|
||||
of BoolTy:
|
||||
dest.add "b"
|
||||
dest.addInt g[i].operand
|
||||
of CharTy:
|
||||
dest.add "c"
|
||||
dest.addInt g[i].operand
|
||||
of NameVal, AnnotationVal:
|
||||
dest.add g.lit.strings[LitId g[i].operand]
|
||||
of IntVal, SizeVal, AlignVal, OffsetVal:
|
||||
dest.add $g[i].kind
|
||||
dest.add ' '
|
||||
dest.add $g.lit.numbers[LitId g[i].operand]
|
||||
of VarargsTy:
|
||||
dest.add "..."
|
||||
of APtrTy:
|
||||
dest.add "aptr["
|
||||
toString(dest, g, g.elementType(i))
|
||||
dest.add "]"
|
||||
of UPtrTy:
|
||||
dest.add "uptr["
|
||||
toString(dest, g, g.elementType(i))
|
||||
dest.add "]"
|
||||
of AArrayPtrTy:
|
||||
dest.add "aArrayPtr["
|
||||
toString(dest, g, g.elementType(i))
|
||||
dest.add "]"
|
||||
of UArrayPtrTy:
|
||||
dest.add "uArrayPtr["
|
||||
toString(dest, g, g.elementType(i))
|
||||
dest.add "]"
|
||||
of ArrayTy:
|
||||
dest.add "Array["
|
||||
let (elems, len, name) = g.sons3(i)
|
||||
toString(dest, g, elems)
|
||||
dest.add ", "
|
||||
toString(dest, g, len)
|
||||
dest.add ", "
|
||||
toString(dest, g, name)
|
||||
dest.add "]"
|
||||
of LastArrayTy:
|
||||
# array of unspecified size as a last field inside an object
|
||||
dest.add "LastArrayTy["
|
||||
toString(dest, g, g.elementType(i))
|
||||
dest.add "]"
|
||||
of ObjectTy:
|
||||
dest.add "object "
|
||||
dest.add g.lit.strings[LitId g[i].operand]
|
||||
of UnionTy:
|
||||
dest.add "union "
|
||||
dest.add g.lit.strings[LitId g[i].operand]
|
||||
of ProcTy:
|
||||
dest.add "proc["
|
||||
for t in sons(g, i):
|
||||
dest.add ' '
|
||||
toString(dest, g, t)
|
||||
dest.add "]"
|
||||
of ObjectDecl:
|
||||
dest.add "object["
|
||||
for t in sons(g, i):
|
||||
toString(dest, g, t)
|
||||
dest.add '\n'
|
||||
dest.add "]"
|
||||
of UnionDecl:
|
||||
dest.add "union["
|
||||
for t in sons(g, i):
|
||||
toString(dest, g, t)
|
||||
dest.add '\n'
|
||||
dest.add "]"
|
||||
of FieldDecl:
|
||||
dest.add "field["
|
||||
for t in sons(g, i):
|
||||
toString(dest, g, t)
|
||||
dest.add ' '
|
||||
dest.add "]"
|
||||
|
||||
when false:
|
||||
let (typ, offset, name) = g.sons3(i)
|
||||
toString(dest, g, typ)
|
||||
dest.add ' '
|
||||
toString(dest, g, offset)
|
||||
dest.add ' '
|
||||
toString(dest, g, name)
|
||||
|
||||
proc toString*(dest: var string; g: TypeGraph) =
|
||||
var i = 0
|
||||
while i < g.len:
|
||||
dest.add "T<"
|
||||
dest.addInt i
|
||||
dest.add "> "
|
||||
toString(dest, g, TypeId i)
|
||||
dest.add '\n'
|
||||
nextChild g, i
|
||||
|
||||
iterator allTypes*(g: TypeGraph; start = 0): TypeId =
|
||||
var i = start
|
||||
while i < g.len:
|
||||
yield TypeId i
|
||||
nextChild g, i
|
||||
|
||||
iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
|
||||
var i = start
|
||||
while i < g.len:
|
||||
yield TypeId i
|
||||
inc i
|
||||
|
||||
proc `$`(g: TypeGraph): string =
|
||||
result = ""
|
||||
toString(result, g)
|
||||
|
||||
when isMainModule:
|
||||
var g = initTypeGraph(Literals())
|
||||
|
||||
let a = g.openType ArrayTy
|
||||
g.addBuiltinType Int8Id
|
||||
g.addArrayLen 5
|
||||
g.addName "SomeArray"
|
||||
let finalArrayType = finishType(g, a)
|
||||
|
||||
let obj = g.openType ObjectDecl
|
||||
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
|
||||
|
||||
g.addField "p", finalArrayType, 0
|
||||
sealType(g, obj)
|
||||
|
||||
echo g
|
||||
1175
compiler/nir/nirvm.nim
Normal file
1175
compiler/nir/nirvm.nim
Normal file
File diff suppressed because it is too large
Load Diff
200
compiler/nir/stringcases.nim
Normal file
200
compiler/nir/stringcases.nim
Normal file
@@ -0,0 +1,200 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## included from ast2ir.nim
|
||||
|
||||
#[
|
||||
|
||||
case s
|
||||
of "abc", "abbd":
|
||||
echo 1
|
||||
of "hah":
|
||||
echo 2
|
||||
of "gah":
|
||||
echo 3
|
||||
|
||||
# we produce code like this:
|
||||
|
||||
if s[0] <= 'a':
|
||||
if s == "abc: goto L1
|
||||
elif s == "abbd": goto L1
|
||||
else:
|
||||
if s[2] <= 'h':
|
||||
if s == "hah": goto L2
|
||||
elif s == "gah": goto L3
|
||||
goto afterCase
|
||||
|
||||
L1:
|
||||
echo 1
|
||||
goto afterCase
|
||||
L2:
|
||||
echo 2
|
||||
goto afterCase
|
||||
L3:
|
||||
echo 3
|
||||
goto afterCase
|
||||
|
||||
afterCase: ...
|
||||
|
||||
]#
|
||||
|
||||
# We split the set of strings into 2 sets of roughly the same size.
|
||||
# The condition used for splitting is a (position, char) tuple.
|
||||
# Every string of length > position for which s[position] <= char is in one
|
||||
# set else it is in the other set.
|
||||
|
||||
from std/sequtils import addUnique
|
||||
|
||||
type
|
||||
Key = (LitId, LabelId)
|
||||
|
||||
proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) =
|
||||
var cand: seq[char] = @[]
|
||||
for t in items a:
|
||||
let s = strings[t[0]]
|
||||
if s.len > position: cand.addUnique s[position]
|
||||
|
||||
result = ('\0', -1.0)
|
||||
for disc in items cand:
|
||||
var hits = 0
|
||||
for t in items a:
|
||||
let s = strings[t[0]]
|
||||
if s.len > position and s[position] <= disc:
|
||||
inc hits
|
||||
# the split is the better, the more `hits` is close to `a.len / 2`:
|
||||
let grade = 100000.0 - abs(hits.float - a.len.float / 2.0)
|
||||
if grade > result[1]:
|
||||
result = (disc, grade)
|
||||
|
||||
proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) =
|
||||
var m = 0
|
||||
for t in items a:
|
||||
m = max(m, strings[t[0]].len)
|
||||
|
||||
result = ('\0', -1)
|
||||
var best = -1.0
|
||||
for i in 0 ..< m:
|
||||
let current = splitValue(strings, a, i)
|
||||
if current[1] > best:
|
||||
best = current[1]
|
||||
result = (current[0], i)
|
||||
|
||||
type
|
||||
SearchKind = enum
|
||||
LinearSearch, SplitSearch
|
||||
SearchResult* = object
|
||||
case kind: SearchKind
|
||||
of LinearSearch:
|
||||
a: seq[Key]
|
||||
of SplitSearch:
|
||||
span: int
|
||||
best: (char, int)
|
||||
|
||||
proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
|
||||
var d = SearchResult(kind: LinearSearch, a: @[])
|
||||
for x in a: d.a.add x
|
||||
dest.add d
|
||||
|
||||
proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
|
||||
if a.len <= 4:
|
||||
emitLinearSearch strings, a, dest
|
||||
else:
|
||||
let best = tryAllPositions(strings, a)
|
||||
var groupA: seq[Key] = @[]
|
||||
var groupB: seq[Key] = @[]
|
||||
for t in items a:
|
||||
let s = strings[t[0]]
|
||||
if s.len > best[1] and s[best[1]] <= best[0]:
|
||||
groupA.add t
|
||||
else:
|
||||
groupB.add t
|
||||
if groupA.len == 0 or groupB.len == 0:
|
||||
emitLinearSearch strings, a, dest
|
||||
else:
|
||||
let toPatch = dest.len
|
||||
dest.add SearchResult(kind: SplitSearch, span: 1, best: best)
|
||||
split strings, groupA, dest
|
||||
split strings, groupB, dest
|
||||
let dist = dest.len - toPatch
|
||||
assert dist > 0
|
||||
dest[toPatch].span = dist
|
||||
|
||||
proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) =
|
||||
result = (@[], newLabels(c.labelGen, n.len))
|
||||
assert n.kind == nkCaseStmt
|
||||
for i in 1..<n.len:
|
||||
let it = n[i]
|
||||
let thisBranch = LabelId(result[1].int + i - 1)
|
||||
if it.kind == nkOfBranch:
|
||||
for j in 0..<it.len-1:
|
||||
assert it[j].kind in {nkStrLit..nkTripleStrLit}
|
||||
result[0].add (c.lit.strings.getOrIncl(it[j].strVal), thisBranch)
|
||||
|
||||
proc decodeSolution(c: var ProcCon; dest: var Tree; s: seq[SearchResult]; i: int;
|
||||
selector: Value; info: PackedLineInfo) =
|
||||
case s[i].kind
|
||||
of SplitSearch:
|
||||
let thenA = i+1
|
||||
let elseA = thenA + (if s[thenA].kind == LinearSearch: 1 else: s[thenA].span)
|
||||
let best = s[i].best
|
||||
|
||||
let tmp = getTemp(c, Bool8Id, info)
|
||||
buildTyped dest, info, Asgn, Bool8Id:
|
||||
dest.copyTree tmp
|
||||
buildTyped dest, info, Call, Bool8Id:
|
||||
c.addUseCodegenProc dest, "nimStrAtLe", info
|
||||
dest.copyTree selector
|
||||
dest.addIntVal c.lit.numbers, info, c.m.nativeIntId, best[1]
|
||||
dest.addIntVal c.lit.numbers, info, Char8Id, best[0].int
|
||||
|
||||
template then() =
|
||||
c.decodeSolution dest, s, thenA, selector, info
|
||||
template otherwise() =
|
||||
c.decodeSolution dest, s, elseA, selector, info
|
||||
buildIfThenElse tmp, then, otherwise
|
||||
freeTemp c, tmp
|
||||
|
||||
of LinearSearch:
|
||||
let tmp = getTemp(c, Bool8Id, info)
|
||||
for x in s[i].a:
|
||||
buildTyped dest, info, Asgn, Bool8Id:
|
||||
dest.copyTree tmp
|
||||
buildTyped dest, info, Call, Bool8Id:
|
||||
c.addUseCodegenProc dest, "eqStrings", info
|
||||
dest.copyTree selector
|
||||
dest.addStrLit info, x[0]
|
||||
buildIf tmp:
|
||||
c.code.gotoLabel info, Goto, x[1]
|
||||
freeTemp c, tmp
|
||||
|
||||
proc genStringCase(c: var ProcCon; n: PNode; d: var Value) =
|
||||
let (problem, firstBranch) = toProblemDescription(c, n)
|
||||
var solution: seq[SearchResult] = @[]
|
||||
split c.lit.strings, problem, solution
|
||||
|
||||
# XXX Todo move complex case selector into a temporary.
|
||||
let selector = c.genx(n[0])
|
||||
|
||||
let info = toLineInfo(c, n.info)
|
||||
decodeSolution c, c.code, solution, 0, selector, info
|
||||
|
||||
let lend = newLabel(c.labelGen)
|
||||
c.code.addLabel info, Goto, lend
|
||||
for i in 1..<n.len:
|
||||
let it = n[i]
|
||||
let thisBranch = LabelId(firstBranch.int + i - 1)
|
||||
c.code.addLabel info, Label, thisBranch
|
||||
if it.kind == nkOfBranch:
|
||||
gen(c, it.lastSon, d)
|
||||
c.code.addLabel info, Goto, lend
|
||||
else:
|
||||
gen(c, it.lastSon, d)
|
||||
|
||||
c.code.addLabel info, Label, lend
|
||||
freeTemp c, selector
|
||||
525
compiler/nir/types2ir.nim
Normal file
525
compiler/nir/types2ir.nim
Normal file
@@ -0,0 +1,525 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2023 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import std / [assertions, tables, sets]
|
||||
import ".." / [ast, types, options, sighashes, modulegraphs]
|
||||
import nirtypes
|
||||
|
||||
type
|
||||
TypesCon* = object
|
||||
processed: Table[ItemId, TypeId]
|
||||
processedByName: Table[string, TypeId]
|
||||
recursionCheck: HashSet[ItemId]
|
||||
conf: ConfigRef
|
||||
stringType: TypeId
|
||||
|
||||
proc initTypesCon*(conf: ConfigRef): TypesCon =
|
||||
TypesCon(conf: conf, stringType: TypeId(-1))
|
||||
|
||||
proc mangle(c: var TypesCon; t: PType): string =
|
||||
result = $sighashes.hashType(t, c.conf)
|
||||
|
||||
template cached(c: var TypesCon; t: PType; body: untyped) =
|
||||
result = c.processed.getOrDefault(t.itemId)
|
||||
if result.int == 0:
|
||||
body
|
||||
c.processed[t.itemId] = result
|
||||
|
||||
template cachedByName(c: var TypesCon; t: PType; body: untyped) =
|
||||
let key = mangle(c, t)
|
||||
result = c.processedByName.getOrDefault(key)
|
||||
if result.int == 0:
|
||||
body
|
||||
c.processedByName[key] = result
|
||||
|
||||
proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
|
||||
|
||||
proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
collectFieldTypes(c, g, n[i], dest)
|
||||
of nkRecCase:
|
||||
assert(n[0].kind == nkSym)
|
||||
collectFieldTypes(c, g, n[0], dest)
|
||||
for i in 1..<n.len:
|
||||
case n[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
collectFieldTypes c, g, lastSon(n[i]), dest
|
||||
else: discard
|
||||
of nkSym:
|
||||
dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ)
|
||||
else:
|
||||
assert false, "unknown node kind: " & $n.kind
|
||||
|
||||
proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
objectToIr(c, g, n[i], fieldTypes, unionId)
|
||||
of nkRecCase:
|
||||
assert(n[0].kind == nkSym)
|
||||
objectToIr(c, g, n[0], fieldTypes, unionId)
|
||||
let u = openType(g, UnionDecl)
|
||||
g.addName "u_" & $unionId
|
||||
inc unionId
|
||||
for i in 1..<n.len:
|
||||
case n[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
let subObj = openType(g, ObjectDecl)
|
||||
g.addName "uo_" & $unionId & "_" & $i
|
||||
objectToIr c, g, lastSon(n[i]), fieldTypes, unionId
|
||||
sealType(g, subObj)
|
||||
else: discard
|
||||
sealType(g, u)
|
||||
of nkSym:
|
||||
g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset
|
||||
else:
|
||||
assert false, "unknown node kind: " & $n.kind
|
||||
|
||||
proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
if t[0] != nil:
|
||||
# ensure we emitted the base type:
|
||||
discard typeToIr(c, g, t[0])
|
||||
|
||||
var unionId = 0
|
||||
var fieldTypes = initTable[ItemId, TypeId]()
|
||||
collectFieldTypes c, g, t.n, fieldTypes
|
||||
let obj = openType(g, ObjectDecl)
|
||||
g.addName mangle(c, t)
|
||||
g.addSize c.conf.getSize(t)
|
||||
g.addAlign c.conf.getAlign(t)
|
||||
|
||||
if t[0] != nil:
|
||||
g.addNominalType(ObjectTy, mangle(c, t[0]))
|
||||
else:
|
||||
g.addBuiltinType VoidId # object does not inherit
|
||||
if not lacksMTypeField(t):
|
||||
let f2 = g.openType FieldDecl
|
||||
let voidPtr = openType(g, APtrTy)
|
||||
g.addBuiltinType(VoidId)
|
||||
sealType(g, voidPtr)
|
||||
g.addOffset 0 # type field is always at offset 0
|
||||
g.addName "m_type"
|
||||
sealType(g, f2) # FieldDecl
|
||||
|
||||
objectToIr c, g, t.n, fieldTypes, unionId
|
||||
result = finishType(g, obj)
|
||||
|
||||
proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
result = g.nominalType(ObjectTy, mangle(c, t))
|
||||
|
||||
proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
var fieldTypes = newSeq[TypeId](t.len)
|
||||
for i in 0..<t.len:
|
||||
fieldTypes[i] = typeToIr(c, g, t[i])
|
||||
let obj = openType(g, ObjectDecl)
|
||||
g.addName mangle(c, t)
|
||||
g.addSize c.conf.getSize(t)
|
||||
g.addAlign c.conf.getAlign(t)
|
||||
|
||||
var accum = OffsetAccum(maxAlign: 1)
|
||||
for i in 0..<t.len:
|
||||
let child = t[i]
|
||||
g.addField "f_" & $i, fieldTypes[i], accum.offset
|
||||
|
||||
computeSizeAlign(c.conf, child)
|
||||
accum.align(child.align)
|
||||
accum.inc(int32(child.size))
|
||||
result = finishType(g, obj)
|
||||
|
||||
proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId =
|
||||
var fieldTypes = newSeq[TypeId](0)
|
||||
for i in 0..<t.len:
|
||||
if t[i] == nil or not isCompileTimeOnly(t[i]):
|
||||
fieldTypes.add typeToIr(c, g, t[i])
|
||||
let obj = openType(g, ProcTy)
|
||||
|
||||
case t.callConv
|
||||
of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall"
|
||||
of ccStdCall: g.addAnnotation "__stdcall"
|
||||
of ccCDecl: g.addAnnotation "__cdecl"
|
||||
of ccSafeCall: g.addAnnotation "__safecall"
|
||||
of ccSysCall: g.addAnnotation "__syscall"
|
||||
of ccInline: g.addAnnotation "__inline"
|
||||
of ccNoInline: g.addAnnotation "__noinline"
|
||||
of ccThisCall: g.addAnnotation "__thiscall"
|
||||
of ccNoConvention: g.addAnnotation ""
|
||||
|
||||
for i in 0..<fieldTypes.len:
|
||||
g.addType fieldTypes[i]
|
||||
|
||||
if addEnv:
|
||||
let a = openType(g, APtrTy)
|
||||
g.addBuiltinType(VoidId)
|
||||
sealType(g, a)
|
||||
|
||||
if tfVarargs in t.flags:
|
||||
g.addVarargs()
|
||||
result = finishType(g, obj)
|
||||
|
||||
proc nativeInt(c: TypesCon): TypeId =
|
||||
case c.conf.target.intSize
|
||||
of 2: result = Int16Id
|
||||
of 4: result = Int32Id
|
||||
else: result = Int64Id
|
||||
|
||||
proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
let e = lastSon(t)
|
||||
let elementType = typeToIr(c, g, e)
|
||||
let arr = g.openType AArrayPtrTy
|
||||
g.addType elementType
|
||||
result = finishType(g, arr) # LastArrayTy
|
||||
|
||||
proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
# object (a: ArrayPtr[T], len: int)
|
||||
let e = lastSon(t)
|
||||
let mangledBase = mangle(c, e)
|
||||
let typeName = "NimOpenArray" & mangledBase
|
||||
|
||||
let elementType = typeToIr(c, g, e)
|
||||
#assert elementType.int >= 0, typeToString(t)
|
||||
|
||||
let p = openType(g, ObjectDecl)
|
||||
g.addName typeName
|
||||
g.addSize c.conf.target.ptrSize*2
|
||||
g.addAlign c.conf.target.ptrSize
|
||||
|
||||
let f = g.openType FieldDecl
|
||||
let arr = g.openType AArrayPtrTy
|
||||
g.addType elementType
|
||||
sealType(g, arr) # LastArrayTy
|
||||
g.addOffset 0
|
||||
g.addName "data"
|
||||
sealType(g, f) # FieldDecl
|
||||
|
||||
g.addField "len", c.nativeInt, c.conf.target.ptrSize
|
||||
|
||||
result = finishType(g, p) # ObjectDecl
|
||||
|
||||
proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) =
|
||||
result = ("NimStrPayload", TypeId(-1))
|
||||
let p = openType(g, ObjectDecl)
|
||||
g.addName result[0]
|
||||
g.addSize c.conf.target.ptrSize*2
|
||||
g.addAlign c.conf.target.ptrSize
|
||||
|
||||
g.addField "cap", c.nativeInt, 0
|
||||
|
||||
let f = g.openType FieldDecl
|
||||
let arr = g.openType LastArrayTy
|
||||
g.addBuiltinType Char8Id
|
||||
result[1] = finishType(g, arr) # LastArrayTy
|
||||
g.addOffset c.conf.target.ptrSize # comes after the len field
|
||||
g.addName "data"
|
||||
sealType(g, f) # FieldDecl
|
||||
|
||||
sealType(g, p)
|
||||
|
||||
proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) =
|
||||
let (mangled, arrayType) = strPayloadType(c, g)
|
||||
let ffp = g.openType APtrTy
|
||||
g.addNominalType ObjectTy, mangled
|
||||
result = (finishType(g, ffp), arrayType) # APtrTy
|
||||
|
||||
proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId =
|
||||
#[
|
||||
|
||||
NimStrPayload = object
|
||||
cap: int
|
||||
data: UncheckedArray[char]
|
||||
|
||||
NimStringV2 = object
|
||||
len: int
|
||||
p: ptr NimStrPayload
|
||||
|
||||
]#
|
||||
let payload = strPayloadType(c, g)
|
||||
|
||||
let str = openType(g, ObjectDecl)
|
||||
g.addName "NimStringV2"
|
||||
g.addSize c.conf.target.ptrSize*2
|
||||
g.addAlign c.conf.target.ptrSize
|
||||
|
||||
g.addField "len", c.nativeInt, 0
|
||||
|
||||
let fp = g.openType FieldDecl
|
||||
let ffp = g.openType APtrTy
|
||||
g.addNominalType ObjectTy, "NimStrPayload"
|
||||
sealType(g, ffp) # APtrTy
|
||||
g.addOffset c.conf.target.ptrSize # comes after 'len' field
|
||||
g.addName "p"
|
||||
sealType(g, fp) # FieldDecl
|
||||
|
||||
result = finishType(g, str) # ObjectDecl
|
||||
|
||||
proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) =
|
||||
#[
|
||||
NimSeqPayload[T] = object
|
||||
cap: int
|
||||
data: UncheckedArray[T]
|
||||
]#
|
||||
let e = lastSon(t)
|
||||
result = (mangle(c, e), TypeId(-1))
|
||||
let payloadName = "NimSeqPayload" & result[0]
|
||||
|
||||
let elementType = typeToIr(c, g, e)
|
||||
|
||||
let p = openType(g, ObjectDecl)
|
||||
g.addName payloadName
|
||||
g.addSize c.conf.target.intSize
|
||||
g.addAlign c.conf.target.intSize
|
||||
|
||||
g.addField "cap", c.nativeInt, 0
|
||||
|
||||
let f = g.openType FieldDecl
|
||||
let arr = g.openType LastArrayTy
|
||||
g.addType elementType
|
||||
# DO NOT USE `finishType` here as it is an inner type. This is subtle and we
|
||||
# probably need an even better API here.
|
||||
sealType(g, arr)
|
||||
result[1] = TypeId(arr)
|
||||
|
||||
g.addOffset c.conf.target.ptrSize
|
||||
g.addName "data"
|
||||
sealType(g, f) # FieldDecl
|
||||
|
||||
sealType(g, p)
|
||||
|
||||
proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) =
|
||||
let (mangledBase, arrayType) = seqPayloadType(c, g, t)
|
||||
let ffp = g.openType APtrTy
|
||||
g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
|
||||
result = (finishType(g, ffp), arrayType) # APtrTy
|
||||
|
||||
proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
#[
|
||||
NimSeqV2*[T] = object
|
||||
len: int
|
||||
p: ptr NimSeqPayload[T]
|
||||
]#
|
||||
let (mangledBase, _) = seqPayloadType(c, g, t)
|
||||
|
||||
let sq = openType(g, ObjectDecl)
|
||||
g.addName "NimSeqV2" & mangledBase
|
||||
g.addSize c.conf.getSize(t)
|
||||
g.addAlign c.conf.getAlign(t)
|
||||
|
||||
g.addField "len", c.nativeInt, 0
|
||||
|
||||
let fp = g.openType FieldDecl
|
||||
let ffp = g.openType APtrTy
|
||||
g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
|
||||
sealType(g, ffp) # APtrTy
|
||||
g.addOffset c.conf.target.ptrSize
|
||||
g.addName "p"
|
||||
sealType(g, fp) # FieldDecl
|
||||
|
||||
result = finishType(g, sq) # ObjectDecl
|
||||
|
||||
|
||||
proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
# struct {fn(args, void* env), env}
|
||||
# typedef struct {$n" &
|
||||
# "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
|
||||
# "void* ClE_0;$n} $1;$n"
|
||||
let mangledBase = mangle(c, t)
|
||||
let typeName = "NimClosure" & mangledBase
|
||||
|
||||
let procType = procToIr(c, g, t, addEnv=true)
|
||||
|
||||
let p = openType(g, ObjectDecl)
|
||||
g.addName typeName
|
||||
g.addSize c.conf.getSize(t)
|
||||
g.addAlign c.conf.getAlign(t)
|
||||
|
||||
let f = g.openType FieldDecl
|
||||
g.addType procType
|
||||
g.addOffset 0
|
||||
g.addName "ClP_0"
|
||||
sealType(g, f) # FieldDecl
|
||||
|
||||
let f2 = g.openType FieldDecl
|
||||
let voidPtr = openType(g, APtrTy)
|
||||
g.addBuiltinType(VoidId)
|
||||
sealType(g, voidPtr)
|
||||
|
||||
g.addOffset c.conf.target.ptrSize
|
||||
g.addName "ClE_0"
|
||||
sealType(g, f2) # FieldDecl
|
||||
|
||||
result = finishType(g, p) # ObjectDecl
|
||||
|
||||
proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
let s = int(getSize(c.conf, t))
|
||||
case s
|
||||
of 1: result = UInt8Id
|
||||
of 2: result = UInt16Id
|
||||
of 4: result = UInt32Id
|
||||
of 8: result = UInt64Id
|
||||
else: result = UInt8Id
|
||||
|
||||
proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
|
||||
if t == nil: return VoidId
|
||||
case t.kind
|
||||
of tyInt:
|
||||
case int(getSize(c.conf, t))
|
||||
of 2: result = Int16Id
|
||||
of 4: result = Int32Id
|
||||
else: result = Int64Id
|
||||
of tyInt8: result = Int8Id
|
||||
of tyInt16: result = Int16Id
|
||||
of tyInt32: result = Int32Id
|
||||
of tyInt64: result = Int64Id
|
||||
of tyFloat:
|
||||
case int(getSize(c.conf, t))
|
||||
of 4: result = Float32Id
|
||||
else: result = Float64Id
|
||||
of tyFloat32: result = Float32Id
|
||||
of tyFloat64: result = Float64Id
|
||||
of tyFloat128: result = getFloat128Type(g)
|
||||
of tyUInt:
|
||||
case int(getSize(c.conf, t))
|
||||
of 2: result = UInt16Id
|
||||
of 4: result = UInt32Id
|
||||
else: result = UInt64Id
|
||||
of tyUInt8: result = UInt8Id
|
||||
of tyUInt16: result = UInt16Id
|
||||
of tyUInt32: result = UInt32Id
|
||||
of tyUInt64: result = UInt64Id
|
||||
of tyBool: result = Bool8Id
|
||||
of tyChar: result = Char8Id
|
||||
of tyVoid: result = VoidId
|
||||
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
|
||||
result = typeToIr(c, g, t.lastSon)
|
||||
of tyEnum:
|
||||
if firstOrd(c.conf, t) < 0:
|
||||
result = Int32Id
|
||||
else:
|
||||
case int(getSize(c.conf, t))
|
||||
of 1: result = UInt8Id
|
||||
of 2: result = UInt16Id
|
||||
of 4: result = Int32Id
|
||||
of 8: result = Int64Id
|
||||
else: result = Int32Id
|
||||
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
|
||||
if t.len > 0:
|
||||
result = typeToIr(c, g, t.lastSon)
|
||||
else:
|
||||
result = TypeId(-1)
|
||||
of tyFromExpr:
|
||||
if t.n != nil and t.n.typ != nil:
|
||||
result = typeToIr(c, g, t.n.typ)
|
||||
else:
|
||||
result = TypeId(-1)
|
||||
of tyArray:
|
||||
cached(c, t):
|
||||
var n = toInt64(lengthOrd(c.conf, t))
|
||||
if n <= 0: n = 1 # make an array of at least one element
|
||||
let elemType = typeToIr(c, g, t[1])
|
||||
let a = openType(g, ArrayTy)
|
||||
g.addType(elemType)
|
||||
g.addArrayLen n
|
||||
g.addName mangle(c, t)
|
||||
result = finishType(g, a)
|
||||
of tyPtr, tyRef:
|
||||
cached(c, t):
|
||||
let e = t.lastSon
|
||||
if e.kind == tyUncheckedArray:
|
||||
let elemType = typeToIr(c, g, e.lastSon)
|
||||
let a = openType(g, AArrayPtrTy)
|
||||
g.addType(elemType)
|
||||
result = finishType(g, a)
|
||||
else:
|
||||
let elemType = typeToIr(c, g, t.lastSon)
|
||||
let a = openType(g, APtrTy)
|
||||
g.addType(elemType)
|
||||
result = finishType(g, a)
|
||||
of tyVar, tyLent:
|
||||
cached(c, t):
|
||||
let e = t.lastSon
|
||||
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
# skip the modifier, `var openArray` is a (ptr, len) pair too:
|
||||
result = typeToIr(c, g, e)
|
||||
else:
|
||||
let elemType = typeToIr(c, g, e)
|
||||
let a = openType(g, APtrTy)
|
||||
g.addType(elemType)
|
||||
result = finishType(g, a)
|
||||
of tySet:
|
||||
let s = int(getSize(c.conf, t))
|
||||
case s
|
||||
of 1: result = UInt8Id
|
||||
of 2: result = UInt16Id
|
||||
of 4: result = UInt32Id
|
||||
of 8: result = UInt64Id
|
||||
else:
|
||||
# array[U8, s]
|
||||
cached(c, t):
|
||||
let a = openType(g, ArrayTy)
|
||||
g.addType(UInt8Id)
|
||||
g.addArrayLen s
|
||||
g.addName mangle(c, t)
|
||||
result = finishType(g, a)
|
||||
of tyPointer, tyNil:
|
||||
# tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim
|
||||
let a = openType(g, APtrTy)
|
||||
g.addBuiltinType(VoidId)
|
||||
result = finishType(g, a)
|
||||
of tyObject:
|
||||
# Objects are special as they can be recursive in Nim. This is easily solvable.
|
||||
# We check if we are already "processing" t. If so, we produce `ObjectTy`
|
||||
# instead of `ObjectDecl`.
|
||||
cached(c, t):
|
||||
if not c.recursionCheck.containsOrIncl(t.itemId):
|
||||
result = objectToIr(c, g, t)
|
||||
else:
|
||||
result = objectHeaderToIr(c, g, t)
|
||||
of tyTuple:
|
||||
cachedByName(c, t):
|
||||
result = tupleToIr(c, g, t)
|
||||
of tyProc:
|
||||
cached(c, t):
|
||||
if t.callConv == ccClosure:
|
||||
result = closureToIr(c, g, t)
|
||||
else:
|
||||
result = procToIr(c, g, t)
|
||||
of tyVarargs, tyOpenArray:
|
||||
cached(c, t):
|
||||
result = openArrayToIr(c, g, t)
|
||||
of tyString:
|
||||
if c.stringType.int < 0:
|
||||
result = stringToIr(c, g)
|
||||
c.stringType = result
|
||||
else:
|
||||
result = c.stringType
|
||||
of tySequence:
|
||||
cachedByName(c, t):
|
||||
result = seqToIr(c, g, t)
|
||||
of tyCstring:
|
||||
cached(c, t):
|
||||
let a = openType(g, AArrayPtrTy)
|
||||
g.addBuiltinType Char8Id
|
||||
result = finishType(g, a)
|
||||
of tyUncheckedArray:
|
||||
# We already handled the `ptr UncheckedArray` in a special way.
|
||||
cached(c, t):
|
||||
let elemType = typeToIr(c, g, t.lastSon)
|
||||
let a = openType(g, LastArrayTy)
|
||||
g.addType(elemType)
|
||||
result = finishType(g, a)
|
||||
of tyUntyped, tyTyped:
|
||||
# this avoids a special case for system.echo which is not a generic but
|
||||
# uses `varargs[typed]`:
|
||||
result = VoidId
|
||||
of tyNone, tyEmpty, tyTypeDesc,
|
||||
tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
|
||||
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
|
||||
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
|
||||
result = TypeId(-1)
|
||||
@@ -1,4 +1,4 @@
|
||||
import os
|
||||
import std/os
|
||||
|
||||
proc findNodeJs*(): string {.inline.} =
|
||||
## Find NodeJS executable and return it as a string.
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
## - recognize "all paths lead to 'wasMoved(x)'"
|
||||
|
||||
import
|
||||
ast, renderer, idents, intsets
|
||||
ast, renderer, idents
|
||||
|
||||
from trees import exprStructuralEquivalent
|
||||
|
||||
import std/strutils
|
||||
import std/[strutils, intsets]
|
||||
|
||||
const
|
||||
nfMarkForDeletion = nfNone # faster than a lookup table
|
||||
@@ -66,7 +66,7 @@ proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} =
|
||||
proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool =
|
||||
result = false
|
||||
for i in 0..<branch.len:
|
||||
if exprStructuralEquivalent(branch[i][1].skipAddr, moveTarget,
|
||||
if exprStructuralEquivalent(branch[i][1].skipHiddenAddr, moveTarget,
|
||||
strictSymEquality = true):
|
||||
result = true
|
||||
matches.incl i
|
||||
@@ -76,7 +76,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
|
||||
var i = 0
|
||||
var matches = initIntSet()
|
||||
while i < summary.len:
|
||||
if wasMovedTarget(matches, branch, summary[i][1].skipAddr):
|
||||
if wasMovedTarget(matches, branch, summary[i][1].skipHiddenAddr):
|
||||
inc i
|
||||
else:
|
||||
summary.del i
|
||||
@@ -87,7 +87,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
|
||||
proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
|
||||
var i = 0
|
||||
while i < c.wasMovedLocs.len:
|
||||
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipAddr, x,
|
||||
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipHiddenAddr, x,
|
||||
strictSymEquality = true):
|
||||
c.wasMovedLocs.del i
|
||||
else:
|
||||
@@ -96,7 +96,7 @@ proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
|
||||
proc wasMovedDestroyPair(c: var Con; b: var BasicBlock; d: PNode) =
|
||||
var i = 0
|
||||
while i < b.wasMovedLocs.len:
|
||||
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipAddr, d[1].skipAddr,
|
||||
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipHiddenAddr, d[1].skipHiddenAddr,
|
||||
strictSymEquality = true):
|
||||
b.wasMovedLocs[i].flags.incl nfMarkForDeletion
|
||||
c.somethingTodo = true
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
#
|
||||
|
||||
import
|
||||
os, strutils, strtabs, sets, lineinfos, platform,
|
||||
prefixmatches, pathutils, nimpaths, tables
|
||||
lineinfos, platform,
|
||||
prefixmatches, pathutils, nimpaths
|
||||
|
||||
from terminal import isatty
|
||||
from times import utc, fromUnix, local, getTime, format, DateTime
|
||||
import std/[tables, os, strutils, strtabs, sets]
|
||||
from std/terminal import isatty
|
||||
from std/times import utc, fromUnix, local, getTime, format, DateTime
|
||||
from std/private/globs import nativeToUnixPath
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
@@ -137,16 +138,19 @@ type
|
||||
backendCpp = "cpp"
|
||||
backendJs = "js"
|
||||
backendObjc = "objc"
|
||||
backendNir = "nir"
|
||||
# backendNimscript = "nimscript" # this could actually work
|
||||
# backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
|
||||
|
||||
Command* = enum ## Nim's commands
|
||||
cmdNone # not yet processed command
|
||||
cmdUnknown # command unmapped
|
||||
cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS
|
||||
cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS,
|
||||
cmdCompileToNir,
|
||||
cmdCrun # compile and run in nimache
|
||||
cmdTcc # run the project via TCC backend
|
||||
cmdCheck # semantic checking for whole project
|
||||
cmdM # only compile a single
|
||||
cmdParse # parse a single file (for debugging)
|
||||
cmdRod # .rod to some text representation (for debugging)
|
||||
cmdIdeTools # ide tools (e.g. nimsuggest)
|
||||
@@ -170,7 +174,8 @@ type
|
||||
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
|
||||
|
||||
const
|
||||
cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCrun}
|
||||
cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||
cmdCompileToJS, cmdCrun, cmdCompileToNir}
|
||||
cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
|
||||
cmdCtags, cmdBuildindex}
|
||||
|
||||
@@ -195,7 +200,7 @@ type
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
dotOperators,
|
||||
@@ -221,7 +226,8 @@ type
|
||||
flexibleOptionalParams,
|
||||
strictDefs,
|
||||
strictCaseObjects,
|
||||
inferGenericTypes
|
||||
inferGenericTypes,
|
||||
vtables
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
@@ -235,9 +241,9 @@ type
|
||||
laxEffects
|
||||
## Lax effects system prior to Nim 2.0.
|
||||
verboseTypeMismatch
|
||||
emitGenerics
|
||||
## generics are emitted in the module that contains them.
|
||||
## Useful for libraries that rely on local passC
|
||||
emitGenerics
|
||||
## generics are emitted in the module that contains them.
|
||||
## Useful for libraries that rely on local passC
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
@@ -284,9 +290,24 @@ type
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
inlayHintInfo*: SuggestInlayHint
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
SuggestInlayHintKind* = enum
|
||||
sihkType = "Type",
|
||||
sihkParameter = "Parameter"
|
||||
|
||||
SuggestInlayHint* = ref object
|
||||
kind*: SuggestInlayHintKind
|
||||
line*: int # Starts at 1
|
||||
column*: int # Starts at 0
|
||||
label*: string
|
||||
paddingLeft*: bool
|
||||
paddingRight*: bool
|
||||
allowInsert*: bool
|
||||
tooltip*: string
|
||||
|
||||
ProfileInfo* = object
|
||||
time*: float
|
||||
count*: int
|
||||
@@ -421,6 +442,9 @@ type
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
currentConfigDir*: string # used for passPP only; absolute dir
|
||||
clientProcessId*: int
|
||||
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
@@ -585,6 +609,7 @@ proc newConfigRef*(): ConfigRef =
|
||||
maxLoopIterationsVM: 10_000_000,
|
||||
vmProfileData: newProfileData(),
|
||||
spellSuggestMax: spellSuggestSecretSauce,
|
||||
currentConfigDir: ""
|
||||
)
|
||||
initConfigRefCommon(result)
|
||||
setTargetFromSystem(result.target)
|
||||
@@ -797,16 +822,17 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
|
||||
else: "_d"
|
||||
|
||||
# XXX projectName should always be without a file extension!
|
||||
result = if not conf.nimcacheDir.isEmpty:
|
||||
conf.nimcacheDir
|
||||
elif conf.backend == backendJs:
|
||||
if conf.outDir.isEmpty:
|
||||
conf.projectPath / genSubDir
|
||||
else:
|
||||
conf.outDir / genSubDir
|
||||
else:
|
||||
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
|
||||
nimcacheSuffix(conf))
|
||||
result =
|
||||
if not conf.nimcacheDir.isEmpty:
|
||||
conf.nimcacheDir
|
||||
elif conf.backend == backendJs:
|
||||
if conf.outDir.isEmpty:
|
||||
conf.projectPath / genSubDir
|
||||
else:
|
||||
conf.outDir / genSubDir
|
||||
else:
|
||||
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
|
||||
nimcacheSuffix(conf))
|
||||
|
||||
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||
let home = removeTrailingDirSep(os.getHomeDir())
|
||||
@@ -884,7 +910,7 @@ const stdlibDirs* = [
|
||||
|
||||
const
|
||||
pkgPrefix = "pkg/"
|
||||
stdPrefix = "std/"
|
||||
stdPrefix* = "std/"
|
||||
|
||||
proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile =
|
||||
result = RelativeFile("")
|
||||
@@ -1064,6 +1090,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
of ideInlayHints: "inlayHints"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
## This module implements the pattern matching features for term rewriting
|
||||
## macro support.
|
||||
|
||||
import strutils, ast, types, msgs, idents, renderer, wordrecg, trees,
|
||||
import ast, types, msgs, idents, renderer, wordrecg, trees,
|
||||
options
|
||||
|
||||
import std/strutils
|
||||
|
||||
# we precompile the pattern here for efficiency into some internal
|
||||
# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
|
||||
# actually improves performance.
|
||||
|
||||
@@ -49,9 +49,11 @@ when isMainModule or defined(nimTestGrammar):
|
||||
checkGrammarFile()
|
||||
|
||||
import
|
||||
llstream, lexer, idents, strutils, ast, msgs, options, lineinfos,
|
||||
llstream, lexer, idents, ast, msgs, options, lineinfos,
|
||||
pathutils
|
||||
|
||||
import std/strutils
|
||||
|
||||
when defined(nimpretty):
|
||||
import layouter
|
||||
|
||||
|
||||
@@ -165,13 +165,13 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
|
||||
|
||||
template processModuleAux(moduleStatus) =
|
||||
onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
|
||||
var s: PLLStream
|
||||
var s: PLLStream = nil
|
||||
if sfMainModule in flags:
|
||||
if graph.config.projectIsStdin: s = stdin.llStreamOpen
|
||||
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
|
||||
discard processModule(graph, result, idGeneratorFromModule(result), s)
|
||||
if result == nil:
|
||||
var cachedModules: seq[FileIndex]
|
||||
var cachedModules: seq[FileIndex] = @[]
|
||||
result = moduleFromRodFile(graph, fileIdx, cachedModules)
|
||||
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
|
||||
if result == nil:
|
||||
@@ -185,7 +185,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayStateChanges(graph.packed.pm[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Path handling utilities for Nim. Strictly typed code in order
|
||||
## to avoid the never ending time sink in getting path handling right.
|
||||
|
||||
import os, pathnorm, strutils
|
||||
import std/[os, pathnorm, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
@@ -11,7 +11,7 @@ when not defined(leanCompiler):
|
||||
import std/[syncio, objectdollar, assertions, tables, strutils]
|
||||
import renderer
|
||||
import ic/replayer
|
||||
|
||||
import nir/nir
|
||||
|
||||
proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
|
||||
graph.pipelinePass = pass
|
||||
@@ -43,6 +43,10 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
|
||||
result = nil
|
||||
of EvalPass, InterpreterPass:
|
||||
result = interpreterCode(bModule, semNode)
|
||||
of NirReplPass:
|
||||
result = runCode(bModule, semNode)
|
||||
of NirPass:
|
||||
result = nirBackend(bModule, semNode)
|
||||
of NonePass:
|
||||
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
|
||||
|
||||
@@ -105,6 +109,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
case graph.pipelinePass
|
||||
of CgenPass:
|
||||
setupCgen(graph, module, idgen)
|
||||
of NirPass:
|
||||
openNirBackend(graph, module, idgen)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
setupJSgen(graph, module, idgen)
|
||||
@@ -112,6 +118,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
nil
|
||||
of EvalPass, InterpreterPass:
|
||||
setupEvalGen(graph, module, idgen)
|
||||
of NirReplPass:
|
||||
setupNirReplGen(graph, module, idgen)
|
||||
of GenDependPass:
|
||||
setupDependPass(graph, module, idgen)
|
||||
of Docgen2Pass:
|
||||
@@ -140,9 +148,10 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
if s == nil:
|
||||
rawMessage(graph.config, errCannotOpenFile, filename.string)
|
||||
return false
|
||||
graph.interactive = false
|
||||
else:
|
||||
s = stream
|
||||
|
||||
graph.interactive = stream.kind == llsStdIn
|
||||
while true:
|
||||
syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)
|
||||
|
||||
@@ -182,21 +191,26 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
case graph.pipelinePass
|
||||
of CgenPass:
|
||||
if bModule != nil:
|
||||
let disps = finalCodegenActions(graph, BModule(bModule), finalNode)
|
||||
if disps != nil:
|
||||
let m = BModule(bModule)
|
||||
finalCodegenActions(graph, m, finalNode)
|
||||
if graph.dispatchers.len > 0:
|
||||
let ctx = preparePContext(graph, module, idgen)
|
||||
for disp in disps:
|
||||
let retTyp = disp.sym.typ[0]
|
||||
for disp in getDispatchers(graph):
|
||||
let retTyp = disp.typ[0]
|
||||
if retTyp != nil:
|
||||
# todo properly semcheck the code of dispatcher?
|
||||
createTypeBoundOps(graph, ctx, retTyp, disp.info, idgen)
|
||||
genProcAux(BModule(bModule), disp.sym)
|
||||
# TODO: properly semcheck the code of dispatcher?
|
||||
createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen)
|
||||
genProcAux(m, disp)
|
||||
discard closePContext(graph, ctx, nil)
|
||||
of JSgenPass:
|
||||
when not defined(leanCompiler):
|
||||
discard finalJSCodeGen(graph, bModule, finalNode)
|
||||
of EvalPass, InterpreterPass:
|
||||
discard interpreterCode(bModule, finalNode)
|
||||
of NirReplPass:
|
||||
discard runCode(bModule, finalNode)
|
||||
of NirPass:
|
||||
closeNirBackend(bModule, finalNode)
|
||||
of SemPass, GenDependPass:
|
||||
discard
|
||||
of Docgen2Pass, Docgen2TexPass:
|
||||
@@ -215,7 +229,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
|
||||
closeRodFile(graph, module)
|
||||
result = true
|
||||
|
||||
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
|
||||
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags; fromModule: PSym = nil): PSym =
|
||||
var flags = flags
|
||||
if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
|
||||
result = graph.getModule(fileIdx)
|
||||
@@ -239,11 +253,18 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
|
||||
else:
|
||||
if sfSystemModule in flags:
|
||||
graph.systemModule = result
|
||||
if sfMainModule in flags and graph.config.cmd == cmdM:
|
||||
result.flags.incl flags
|
||||
registerModule(graph, result)
|
||||
processModuleAux("import")
|
||||
partialInitModule(result, graph, fileIdx, filename)
|
||||
for m in cachedModules:
|
||||
registerModuleById(graph, m)
|
||||
replayStateChanges(graph.packed[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
if sfMainModule in flags and graph.config.cmd == cmdM:
|
||||
discard
|
||||
else:
|
||||
replayStateChanges(graph.packed.pm[m.int].module, graph)
|
||||
replayGenericCacheInformation(graph, m.int)
|
||||
elif graph.isDirty(result):
|
||||
result.flags.excl sfDirty
|
||||
# reset module fields:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# Feel free to test for your excentric platform!
|
||||
|
||||
import
|
||||
strutils
|
||||
std/strutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -32,7 +32,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
|
||||
let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen)
|
||||
|
||||
let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
|
||||
prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc)
|
||||
prc.typ = copyType(iter.sym.typ, c.idgen, prc)
|
||||
excl prc.typ.flags, tfCapturesEnv
|
||||
prc.typ.n.add newSymNode(getEnvParam(iter.sym))
|
||||
prc.typ.rawAddSon t
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
# This module implements semantic checking for pragmas
|
||||
|
||||
import
|
||||
os, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
|
||||
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
|
||||
condsyms, ast, astalgo, idents, semdata, msgs, renderer,
|
||||
wordrecg, ropes, options, extccomp, magicsys, trees,
|
||||
types, lookups, lineinfos, pathutils, linter, modulepaths
|
||||
|
||||
import std/[os, math, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
@@ -72,9 +74,9 @@ const
|
||||
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage, wCodegenDecl,
|
||||
wSendable}
|
||||
wSendable, wNoInit}
|
||||
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
|
||||
wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
|
||||
wRequiresInit, wNoalias, wAlign, wNoInit} - {wExportNims, wNodecl} # why exclude these?
|
||||
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
|
||||
wMagic, wHeader, wCompilerProc, wCore, wDynlib,
|
||||
wNoInit, wCompileTime, wGlobal,
|
||||
@@ -1309,7 +1311,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
|
||||
if sym != nil and sym.kind != skModule:
|
||||
for it in c.optionStack:
|
||||
let o = it.otherPragmas
|
||||
if not o.isNil and sfFromGeneric notin sym.flags: # see issue #12985
|
||||
if not o.isNil:
|
||||
pushInfoContext(c.config, info)
|
||||
var i = 0
|
||||
while i < o.len:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
from strutils import toLowerAscii
|
||||
from std/strutils import toLowerAscii
|
||||
|
||||
type
|
||||
PrefixMatch* {.pure.} = enum
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
# This is needed for proper handling of forward declarations.
|
||||
|
||||
import
|
||||
ast, astalgo, msgs, semdata, types, trees, strutils, lookups
|
||||
ast, astalgo, msgs, semdata, types, trees, lookups
|
||||
|
||||
import std/strutils
|
||||
|
||||
proc equalGenericParams(procA, procB: PNode): bool =
|
||||
if procA.len != procB.len: return false
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
{.used.}
|
||||
|
||||
import
|
||||
lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg
|
||||
lexer, options, idents, ast, msgs, lineinfos, wordrecg
|
||||
|
||||
import std/[strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions, formatfloat]
|
||||
@@ -864,7 +866,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
if renderNoPragmas notin g.flags:
|
||||
gsub(g, n[pragmasPos])
|
||||
if renderNoBody notin g.flags:
|
||||
if n[bodyPos].kind != nkEmpty:
|
||||
if n.len > bodyPos and n[bodyPos].kind != nkEmpty:
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
indentNL(g)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user