got rid of some arcane module names

This commit is contained in:
Araq
2011-04-21 00:54:44 +02:00
parent c3b16311dd
commit 36c67455d4
34 changed files with 327 additions and 1258 deletions

View File

@@ -8,7 +8,7 @@
#
import
strutils, os, times, parseopt, llstream, ast, rnimsyn, options, msgs,
strutils, os, times, parseopt, llstream, ast, renderer, options, msgs,
clex, cparse
const

View File

@@ -14,7 +14,7 @@
# XXX cleanup of declaration handling.
import
os, llstream, rnimsyn, clex, idents, strutils, pegs, ast, astalgo, msgs,
os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
options, strtabs
type

View File

@@ -14,7 +14,7 @@ import
ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp,
options,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, rnimsyn, treetab, cgmeth,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils
when options.hasTinyCBackend:

View File

@@ -10,7 +10,7 @@
## This module implements code generation for multi methods.
import
options, ast, astalgo, msgs, idents, rnimsyn, types, magicsys
options, ast, astalgo, msgs, idents, renderer, types, magicsys
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var

View File

@@ -13,7 +13,7 @@
import
ast, astalgo, strutils, nhashes, options, nversion, msgs, os, ropes, idents,
wordrecg, math, syntaxes, rnimsyn, scanner, rst, times, highlite
wordrecg, math, syntaxes, renderer, lexer, rst, times, highlite
proc CommandDoc*(filename: string)
proc CommandRst2Html*(filename: string)

View File

@@ -14,7 +14,7 @@
import
ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp,
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
times, ropes, math, passes, ccgutils, wordrecg, rnimsyn, rodread, rodutils
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils
proc ecmasgenPass*(): TPass
# implementation

View File

@@ -15,7 +15,7 @@
import
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
msgs, os, condsyms, idents, rnimsyn, types, passes, semfold
msgs, os, condsyms, idents, renderer, types, passes, semfold
type
PStackFrame* = ref TStackFrame

View File

@@ -11,7 +11,7 @@
import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
rnimsyn, filters
renderer, filters
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream
# #! template(subsChar='$', metaChar='#') | standard(version="0.7.2")

View File

@@ -10,7 +10,8 @@
# This module implements Nimrod's simple filters and helpers for filters.
import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, rnimsyn
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream

View File

@@ -12,7 +12,7 @@
# The interface supports one language nested in another.
import
nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, scanner
nhashes, options, msgs, strutils, platform, idents, lexbase, wordrecg, lexer
type
TTokenClass* = enum
@@ -154,7 +154,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
var id = ""
while g.buf[pos] in scanner.SymChars + {'_'}:
while g.buf[pos] in lexer.SymChars + {'_'}:
add(id, g.buf[pos])
inc(pos)
if (g.buf[pos] == '\"'):
@@ -247,9 +247,9 @@ proc nimNextToken(g: var TGeneralTokenizer) =
of '\0':
g.kind = gtEof
else:
if g.buf[pos] in scanner.OpChars:
if g.buf[pos] in lexer.OpChars:
g.kind = gtOperator
while g.buf[pos] in scanner.OpChars: inc(pos)
while g.buf[pos] in lexer.OpChars: inc(pos)
else:
inc(pos)
g.kind = gtNone
@@ -462,10 +462,10 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
of '\0':
g.kind = gtEof
else:
if g.buf[pos] in scanner.OpChars:
if g.buf[pos] in lexer.OpChars:
g.kind = gtOperator
while g.buf[pos] in scanner.OpChars: inc(pos)
else:
while g.buf[pos] in lexer.OpChars: inc(pos)
else:
inc(pos)
g.kind = gtNone
g.length = pos - g.pos

View File

@@ -10,7 +10,7 @@
# This module implements lookup helpers.
import
ast, astalgo, idents, semdata, types, msgs, options, rodread, rnimsyn
ast, astalgo, idents, semdata, types, msgs, options, rodread, renderer
type
TOverloadIterMode* = enum

View File

@@ -11,7 +11,7 @@
# module handling
import
llstream, strutils, ast, astalgo, scanner, syntaxes, rnimsyn, options, msgs,
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, lists, condsyms, rodread, rodwrite, ropes, trees,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen,

View File

@@ -10,7 +10,7 @@
# This module handles the reading of the config file.
import
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, scanner,
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
options, idents, wordrecg
# ---------------- configuration file parser -----------------------------

View File

@@ -11,7 +11,7 @@ when defined(gcc) and defined(windows):
{.link: "icons/nimrod.res".}
import
times, commands, scanner, condsyms, options, msgs, nversion, nimconf, ropes,
times, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt
when hasTinyCBackend:

View File

@@ -10,7 +10,7 @@
# this unit handles Nimrod sets; it implements symbolic sets
import
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, rnimsyn
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
proc toBitSet*(s: PNode, b: var TBitSet)
# this function is used for case statement checking:
@@ -172,4 +172,4 @@ proc SetHasRange(s: PNode): bool =
proc emptyRange(a, b: PNode): bool =
result = not leValue(a, b) # a > b iff not (a <= b)

View File

@@ -15,7 +15,7 @@
# from the grammar and how comments belong to the AST.
import
llstream, scanner, idents, strutils, ast, msgs
llstream, lexer, idents, strutils, ast, msgs
type
TParser*{.final.} = object # a TParser object represents a module that

View File

@@ -8,7 +8,7 @@
#
import
strutils, os, parseopt, llstream, ast, rnimsyn, options, msgs,
strutils, os, parseopt, llstream, ast, renderer, options, msgs,
paslex, pasparse
const

View File

@@ -12,8 +12,8 @@
import
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, rnimsyn, types, extccomp, math, magicsys, nversion, nimsets,
syntaxes, times, rodread
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread
type
TPassContext* = object of TObject # the pass's context

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,11 @@
#
import
llstream, scanner, idents, strutils, ast, msgs, pnimsyn
llstream, lexer, parser, idents, strutils, ast, msgs
proc ParseAll*(p: var TParser): PNode
proc parseTopLevelStmt*(p: var TParser): PNode
# implements an iterator. Returns the next top-level statement or nil if end
# of stream.
# implementation
proc ParseAll(p: var TParser): PNode =
proc ParseAll*(p: var TParser): PNode =
result = nil
proc parseTopLevelStmt(p: var TParser): PNode =
proc parseTopLevelStmt*(p: var TParser): PNode =
result = nil

View File

@@ -10,7 +10,7 @@
# This module implements semantic checking for pragmas
import
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, rnimsyn,
os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees,
rodread

View File

@@ -10,7 +10,7 @@
# This module implements the renderer of the standard Nimrod representation.
import
scanner, options, idents, strutils, ast, msgs, lists
lexer, options, idents, strutils, ast, msgs, lists
type
TRenderFlag* = enum
@@ -637,7 +637,7 @@ proc gasm(g: var TSrcGen, n: PNode) =
proc gident(g: var TSrcGen, n: PNode) =
var t: TTokType
var s = atom(n)
if (s[0] in scanner.SymChars):
if (s[0] in lexer.SymChars):
if (n.kind == nkIdent):
if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
(n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):

View File

@@ -10,9 +10,9 @@
# This module implements the semantic checking pass.
import
strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math,
magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer,
strutils, nhashes, lists, options, lexer, ast, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, nimsets, semdata, evals, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest
proc semPass*(): TPass

View File

@@ -10,9 +10,9 @@
# This module contains the data structures for the semantic checking phase.
import
strutils, lists, options, scanner, ast, astalgo, trees, treetab, wordrecg,
ropes, msgs, platform, os, condsyms, idents, rnimsyn, types, extccomp, math,
magicsys, nversion, nimsets, pnimsyn, times, passes, rodread
strutils, lists, options, lexer, ast, astalgo, trees, treetab, wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread
type
TOptionEntry* = object of lists.TListEntry # entries to put on a

View File

@@ -12,7 +12,7 @@
import
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, rnimsyn, types,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands
proc getConstExpr*(m: PSym, n: PNode): PNode

View File

@@ -11,7 +11,7 @@
# the call to overloaded procs, generic procs and operators.
import
ast, astalgo, semdata, types, msgs, rnimsyn, lookups, semtypinst,
ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys
type

View File

@@ -9,7 +9,8 @@
## This file implements features required for IDE support.
import scanner, idents, ast, astalgo, semdata, msgs, types, sigmatch, options
import
lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options
const
sep = '\t'
@@ -38,7 +39,7 @@ proc SymToStr(s: PSym, isLocal: bool, section: string): string =
result.add($ToColumn(s.info))
proc filterSym(s: PSym): bool {.inline.} =
result = s.name.s[0] in scanner.SymChars
result = s.name.s[0] in lexer.SymChars
proc suggestField(s: PSym) =
if filterSym(s):

View File

@@ -10,8 +10,8 @@
## Implements the dispatcher for the different parsers.
import
strutils, llstream, ast, astalgo, idents, scanner, options, msgs, pnimsyn,
pbraces, ptmplsyn, filters, rnimsyn
strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
pbraces, filters, filter_tmpl, renderer
type
TFilterKind* = enum
@@ -54,7 +54,7 @@ proc ParseFile(filename: string): PNode =
proc parseAll(p: var TParsers): PNode =
case p.skin
of skinStandard:
result = pnimsyn.parseAll(p.parser)
result = parser.parseAll(p.parser)
of skinBraces:
result = pbraces.parseAll(p.parser)
of skinEndX:
@@ -65,7 +65,7 @@ proc parseAll(p: var TParsers): PNode =
proc parseTopLevelStmt(p: var TParsers): PNode =
case p.skin
of skinStandard:
result = pnimsyn.parseTopLevelStmt(p.parser)
result = parser.parseTopLevelStmt(p.parser)
of skinBraces:
result = pbraces.parseTopLevelStmt(p.parser)
of skinEndX:
@@ -99,7 +99,7 @@ proc parsePipe(filename: string, inputStream: PLLStream): PNode =
while line[i] in WhiteSpace: inc(i)
var q: TParser
OpenParser(q, filename, LLStreamOpen(copy(line, i)))
result = pnimsyn.parseAll(q)
result = parser.parseAll(q)
CloseParser(q)
LLStreamClose(s)
@@ -167,7 +167,7 @@ proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) =
else: s = inputStream
case p.skin
of skinStandard, skinBraces, skinEndX:
pnimsyn.openParser(p.parser, filename, s)
parser.openParser(p.parser, filename, s)
proc closeParsers(p: var TParsers) =
pnimsyn.closeParser(p.parser)
parser.closeParser(p.parser)

View File

@@ -18,7 +18,7 @@
import
strutils, lists, options, ast, astalgo, trees, treetab, evals, msgs, os,
idents, rnimsyn, types, passes, semfold, magicsys, cgmeth
idents, renderer, types, passes, semfold, magicsys, cgmeth
const
genPrefix* = ":tmp" # prefix for generated names

View File

@@ -10,7 +10,7 @@
# tree helper routines
import
ast, astalgo, scanner, msgs, strutils
ast, astalgo, lexer, msgs, strutils
proc getMagic*(op: PNode): TMagic

View File

@@ -9,16 +9,11 @@ nimrod main module: parses the command line and calls
main implements the top-level command dispatching
nimconf implements the config file reader
syntaxes dispatcher for the different parsers and filters
ptmplsyn standard template filter (``#! stdtempl``)
filter_tmpl standard template filter (``#! stdtempl``)
lexbase buffer handling of the lexical analyser
scanner lexical analyser
pnimsyn Nimrod's parser
rnimsyn Nimrod code renderer (AST back to its textual form)
paslex lexer for Pascal
pasparse parser for Pascal; Pascal's advanced OO features are not
supported
lexer lexical analyser
parser Nimrod's parser
renderer Nimrod code renderer (AST back to its textual form)
options contains global and local compiler options
ast type definitions of the abstract syntax tree (AST) and
node constructors

View File

@@ -18,8 +18,8 @@ type
TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
THashTable[A, B] = object of TObject
counter: int
data: TKeyValuePairSeq[A, B]
counter: int
PHashTable*[A, B] = ref THashTable[A, B] ## use this type to declare tables
@@ -32,12 +32,12 @@ iterator pairs*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] =
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
iterator keys*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] =
iterator keys*[A, B](t: PHashTable[A, B]): A =
## iterates over any key in the table `t`.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].key
iterator values*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] =
iterator values*[A, B](t: PHashTable[A, B]): B =
## iterates over any value in the table `t`.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val
@@ -103,6 +103,7 @@ proc del*[A, B](t: PHashTable[A, B], key: A) =
var index = RawGet(t, key)
if index >= 0:
t.data[index].slot = seDeleted
dec(t.counter)
proc newHashTable*[A, B](initialSize = 64): PHashTable[A, B] =
## creates a new string table that is empty. `initialSize` needs to be
@@ -125,6 +126,110 @@ proc `$`*[A, B](t: PHashTable[A, B]): string =
result.add($val)
result.add("}")
# ------------------------------ count tables -------------------------------
const
deletedCount = -1
type
TCountTable*[A] {.final.} = object
data: seq[tuple[key: A, val: int]]
counter: int
proc len*[A](t: TCountTable[A]): int =
## returns the number of keys in `t`.
result = t.counter
iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
## iterates over any (key, value) pair in the table `t`.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
iterator keys*[A](t: TCountTable[A]): A =
## iterates over any key in the table `t`.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].key
iterator values*[A](t: TCountTable[A]): int =
## iterates over any value in the table `t`.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val
proc RawGet[A](t: TCountTable[A], key: A): int =
var h: THash = hash(key) and high(t.data) # start with real hash value
while t.data[h].slot != seEmpty:
if t.data[h].key == key and t.data[h].slot == seFilled:
return h
h = nextTry(h, high(t.data))
result = -1
proc `[]`*[A](t: TCountTable[A], key: A): B =
## retrieves the value at ``t[key]``. If `key` is not in `t`,
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
proc hasKey*[A](t: TCountTable[A], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc RawInsert[A](t: TCountTable[A], data: var TKeyValuePairSeq[A, B],
key: A, val: int) =
var h: THash = hash(key) and high(data)
while data[h].slot == seFilled:
h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
data[h].slot = seFilled
proc Enlarge[A](t: TCountTable[A]) =
var n: TKeyValuePairSeq[A, B]
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc `[]=`*[A](t: TCountTable[A], key: A, val: int) =
## puts a (key, value)-pair into `t`.
var index = RawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
inc(t.counter)
proc del*[A](t: TCountTable[A], key: A) =
## deletes `key` from hash table `t`.
var index = RawGet(t, key)
if index >= 0:
t.data[index].slot = seDeleted
proc newHashTable*[A, B](initialSize = 64): PHashTable[A, B] =
## creates a new string table that is empty. `initialSize` needs to be
## a power of two.
assert isPowerOfTwo(initialSize)
new(result)
result.counter = 0
newSeq(result.data, initialSize)
proc `$`*[A](t: TCountTable[A]): string =
## The `$` operator for string tables.
if t.len == 0:
result = "{:}"
else:
result = "{"
for key, val in pairs(t):
if result.len > 1: result.add(", ")
result.add($key)
result.add(": ")
result.add($val)
result.add("}")
when isMainModule:
var table = newHashTable[string, float]()
table["test"] = 1.2345

155
lib/pure/collections/lists.nim Executable file
View File

@@ -0,0 +1,155 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implementation of singly and doubly linked lists. Because it makes no sense
## to do so, the 'next' and 'prev' pointers are not hidden from you and can
## be manipulated directly for efficiency.
type
TDoublyLinkedNode[T] {.pure, final.} = object
next*, prev*: ref TDoublyLinkedNode[T]
value*: T
PDoublyLinkedNode*[T] = ref TDoublyLinkedNode[T]
TSinglyLinkedNode[T] {.pure, final.} = object
next*: ref TSinglyLinkedNode[T]
value*: T
PSinglyLinkedNode*[T] = ref TSinglyLinkedNode[T]
proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] =
## creates a new doubly linked node with the given `value`.
new(result)
result.value = value
proc newSinglyLinkedNode*[T](value: T): PSinglyLinkedNode[T] =
## creates a new singly linked node with the given `value`.
new(result)
result.value = value
iterator items*[T](n: PDoublyLinkedNode[T]): T =
## yields every value of `x`.
var it = n
while it != nil:
yield it.value
it = it.next
iterator items*[T](n: PSinglyLinkedNode[T]): T =
## yields every value of `x`.
var it = n
while it != nil:
yield it.value
it = it.next
iterator nodes*[T](n: PSinglyLinkedNode[T]): PSinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
var it = n
while it != nil:
var nxt = it.next
yield it
it = nxt
iterator nodes*[T](n: PDoublyLinkedNode[T]): PDoublyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
var it = n
while it != nil:
var nxt = it.next
yield it
it = nxt
proc `$`*[list: PSinglyLinkedNode|PDoublyLinkedNode](n: list): string =
## turns a list into its string representation.
result = "["
for x in nodes(n):
if result.len > 1: result.add(", ")
result.add($x.value)
result.add("]")
proc find*[list: PSinglyLinkedNode|PDoublyLinkedNode, T](
n: list, value: T): list =
## searches in the list for a value. Returns nil if the value does not
## exist.
for x in nodes(n):
if x.value == value: return x
proc contains*[list: PSinglyLinkedNode|PDoublyLinkedNode, T](
n: list, value: T): list =
## searches in the list for a value. Returns false if the value does not
## exist, true otherwise.
for x in nodes(n):
if x.value == value: return true
proc prepend*[T](head: var PSinglyLinkedNode[T],
toAdd: PSinglyLinkedNode[T]) {.inline.} =
## prepends a node to `head`. Efficiency: O(1).
toAdd.next = head
head = toAdd
proc prepend*[T](head: var PSinglyLinkedNode[T], x: T) {.inline.} =
## creates a new node with the value `x` and prepends that node to `head`.
## Efficiency: O(1).
preprend(head, newSinglyLinkedNode(x))
proc append*[T](head: var PSinglyLinkedNode[T],
toAdd: PSinglyLinkedNode[T]) =
## appends a node to `head`. Efficiency: O(n).
if head == nil:
head = toAdd
else:
var it = head
while it.next != nil: it = it.next
it.next = toAdd
proc append*[T](head: var PSinglyLinkedNode[T], x: T) {.inline.} =
## creates a new node with the value `x` and appends that node to `head`.
## Efficiency: O(n).
append(head, newSinglyLinkedNode(x))
proc prepend*[T](head: var PDoublyLinkedNode[T],
toAdd: PDoublyLinkedNode[T]) {.inline.} =
## prepends a node to `head`. Efficiency: O(1).
if head == nil:
head = toAdd
# head.prev stores the last node:
head.prev = toAdd
else:
toAdd.next = head
toAdd.prev = head.prev # copy pointer to last element
head.prev = toAdd
head = toAdd
proc prepend*[T](head: var PDoublyLinkedNode[T], x: T) {.inline.} =
## creates a new node with the value `x` and prepends that node to `head`.
## Efficiency: O(1).
preprend(head, newDoublyLinkedNode(x))
proc append*[T](head: var PDoublyLinkedNode[T],
toAdd: PDoublyLinkedNode[T]) {.inline.} =
## appends a node to `head`. Efficiency: O(1).
if head == nil:
head = toAdd
# head.prev stores the last node:
head.prev = toAdd
else:
var last = head.prev
assert last.next == nil
last.next = toAdd
toAdd.prev = last
head.prev = toAdd # new last element
proc append*[T](head: var PDoublyLinkedNode[T], x: T) {.inline.} =
## creates a new node with the value `x` and appends that node to `head`.
## Efficiency: O(1).
append(head, newDoublyLinkedNode(x))