Merge branch 'devel' of https://github.com/Araq/Nimrod into devel

This commit is contained in:
Andreas Rumpf 2014-04-13 00:40:17 +02:00
commit 2e9950afe8
10 changed files with 313 additions and 85 deletions

View file

@ -564,7 +564,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
moveInto(p, a, r) moveInto(p, a, r)
var i = 1 var i = 1
if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch: if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
appf(p.body, "} catch (EXC) {$n") appf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n")
elif p.target == targetLua: elif p.target == targetLua:
appf(p.body, "end)$n") appf(p.body, "end)$n")
while i < length and n.sons[i].kind == nkExceptBranch: while i < length and n.sons[i].kind == nkExceptBranch:
@ -1114,6 +1114,8 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
var e = elemType(t) var e = elemType(t)
if length > 32: if length > 32:
useMagic(p, "arrayConstr") useMagic(p, "arrayConstr")
# XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
useMagic(p, "nimCopy")
result = ropef("arrayConstr($1, $2, $3)", [toRope(length), result = ropef("arrayConstr($1, $2, $3)", [toRope(length),
createVar(p, e, false), genTypeInfo(p, e)]) createVar(p, e, false), genTypeInfo(p, e)])
else: else:
@ -1314,7 +1316,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
binaryExpr(p, n, r, "", "$1 += $2") binaryExpr(p, n, r, "", "$1 += $2")
else: else:
binaryExpr(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)") binaryExpr(p, n, r, "", "$1 = ($1.slice(0, -1)).concat($2)")
# XXX: make a copy of $2, because of Javascript's sucking semantics # XXX: make a copy of $2, because of Javascript's sucking semantics
of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)") of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)")
of mConStrStr: genConStrStr(p, n, r) of mConStrStr: genConStrStr(p, n, r)
@ -1341,7 +1343,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of ast.mDec: of ast.mDec:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = ($2)-1") of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2") of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2")
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)") of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
@ -1698,7 +1700,12 @@ proc myClose(b: PPassContext, n: PNode): PNode =
var m = BModule(b) var m = BModule(b)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
let code = wholeCode(m) let code = wholeCode(m)
var outfile = changeFileExt(completeCFilePath(m.module.filename), "js") let outfile =
if options.outFile.len > 0:
if options.outFile.isAbsolute: options.outFile
else: getCurrentDir() / options.outFile
else:
changeFileExt(completeCFilePath(m.module.filename), "js")
discard writeRopeIfNotEqual(con(genHeader(), code), outfile) discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =

View file

@ -61,7 +61,11 @@ proc handleCmdLine() =
tccgen.run() tccgen.run()
if optRun in gGlobalOptions: if optRun in gGlobalOptions:
if gCmd == cmdCompileToJS: if gCmd == cmdCompileToJS:
var ex = quoteShell( var ex: string
if options.outFile.len > 0:
ex = options.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & service.arguments) execExternalProgram("node " & ex & ' ' & service.arguments)
else: else:

View file

@ -16,10 +16,11 @@ Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary
while impure libraries do. A wrapper is an impure library that is a very while impure libraries do. A wrapper is an impure library that is a very
low-level interface to a C library. low-level interface to a C library.
Read this `document <apis.html>`_ for a quick overview of the API design. If Read this `document <apis.html>`_ for a quick overview of the API design.
you can't find here some functionality you are looking for you could try using
the 3rd party `package manager Babel <https://github.com/nimrod-code/babel>`_ The `bottom <#babel>`_ of this page includes a list of 3rd party packages
and its list of packages. created by the Nimrod community. These packages are a useful addition to the
modules in the standard library.
Pure libraries Pure libraries
@ -573,3 +574,35 @@ Scientific computing
* `libsvm <libsvm.html>`_ * `libsvm <libsvm.html>`_
Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_. Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
Babel
====================
Babel is a package manager for the Nimrod programming language.
For instructions on how to install Babel packages see
`its README <https://github.com/nimrod-code/babel#readme>`_.
Official packages
-----------------
These packages are officially supported and will therefore be continually
maintained to ensure that they work with the latest versions of the Nimrod
compiler.
.. raw:: html
<div id="officialPkgList"></div>
Unofficial packages
-------------------
These packages have been developed by independent Nimrod developers and as
such may not always be up to date with the latest developments in the
Nimrod programming language.
.. raw:: html
<div id="unofficialPkgList"></div>
<script type="text/javascript" src="babelpkglist.js"></script>
<script type="text/javascript" src="http://build.nimrod-lang.org/packages?callback=gotPackageList"></script>

View file

@ -861,7 +861,8 @@ proc parseJson(p: var TJsonParser): PJsonNode =
of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof: of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof:
raiseParseErr(p, "{") raiseParseErr(p, "{")
proc parseJson*(s: PStream, filename: string): PJsonNode = when not defined(js):
proc parseJson*(s: PStream, filename: string): PJsonNode =
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
## for nice error messages. ## for nice error messages.
var p: TJsonParser var p: TJsonParser
@ -870,16 +871,86 @@ proc parseJson*(s: PStream, filename: string): PJsonNode =
result = p.parseJson() result = p.parseJson()
p.close() p.close()
proc parseJson*(buffer: string): PJsonNode = proc parseJson*(buffer: string): PJsonNode =
## Parses JSON from `buffer`. ## Parses JSON from `buffer`.
result = parseJson(newStringStream(buffer), "input") result = parseJson(newStringStream(buffer), "input")
proc parseFile*(filename: string): PJsonNode = proc parseFile*(filename: string): PJsonNode =
## Parses `file` into a `PJsonNode`. ## Parses `file` into a `PJsonNode`.
var stream = newFileStream(filename, fmRead) var stream = newFileStream(filename, fmRead)
if stream == nil: if stream == nil:
raise newException(EIO, "cannot read from file: " & filename) raise newException(EIO, "cannot read from file: " & filename)
result = parseJson(stream, filename) result = parseJson(stream, filename)
else:
from math import `mod`
type
TJSObject = object
proc parseNativeJson(x: cstring): TJSObject {.importc: "JSON.parse".}
proc getVarType(x): TJsonNodeKind =
result = JNull
proc getProtoName(y): cstring
{.importc: "Object.prototype.toString.call".}
case $getProtoName(x) # TODO: Implicit returns fail here.
of "[object Array]": return JArray
of "[object Object]": return JObject
of "[object Number]":
if cast[float](x) mod 1.0 == 0:
return JInt
else:
return JFloat
of "[object Boolean]": return JBool
of "[object Null]": return JNull
of "[object String]": return JString
else: assert false
proc len(x: TJSObject): int =
assert x.getVarType == JArray
asm """
return `x`.length;
"""
proc `[]`(x: TJSObject, y: string): TJSObject =
assert x.getVarType == JObject
asm """
return `x`[`y`];
"""
proc `[]`(x: TJSObject, y: int): TJSObject =
assert x.getVarType == JArray
asm """
return `x`[`y`];
"""
proc convertObject(x: TJSObject): PJsonNode =
case getVarType(x)
of JArray:
result = newJArray()
for i in 0 .. <x.len:
result.add(x[i].convertObject())
of JObject:
result = newJObject()
asm """for (property in `x`) {
if (`x`.hasOwnProperty(property)) {
"""
var nimProperty: cstring
var nimValue: TJSObject
asm "`nimProperty` = property; `nimValue` = `x`[property];"
result[$nimProperty] = nimValue.convertObject()
asm "}}"
of JInt:
result = newJInt(cast[int](x))
of JFloat:
result = newJFloat(cast[float](x))
of JString:
result = newJString($cast[cstring](x))
of JBool:
result = newJBool(cast[bool](x))
of JNull:
result = newJNull()
proc parseJson*(buffer: string): PJsonNode =
return parseNativeJson(buffer).convertObject()
when false: when false:
import os import os

View file

@ -19,8 +19,8 @@
when defined(Posix) and not defined(haiku): when defined(Posix) and not defined(haiku):
{.passl: "-lm".} {.passl: "-lm".}
when not defined(js):
import times import times
const const
PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number) PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)

View file

@ -239,28 +239,30 @@ proc newStringStream*(s: string = ""): PStringStream =
result.readDataImpl = ssReadData result.readDataImpl = ssReadData
result.writeDataImpl = ssWriteData result.writeDataImpl = ssWriteData
type when not defined(js):
type
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile` PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
TFileStream* = object of TStream TFileStream* = object of TStream
f: TFile f: TFile
proc fsClose(s: PStream) = proc fsClose(s: PStream) =
if PFileStream(s).f != nil: if PFileStream(s).f != nil:
close(PFileStream(s).f) close(PFileStream(s).f)
PFileStream(s).f = nil PFileStream(s).f = nil
proc fsFlush(s: PStream) = flushFile(PFileStream(s).f) proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f) proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f)
proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos) proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f)) proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int = proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
result = readBuffer(PFileStream(s).f, buffer, bufLen) result = readBuffer(PFileStream(s).f, buffer, bufLen)
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) = proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen: if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream") raise newEIO("cannot write to stream")
proc newFileStream*(f: TFile): PFileStream = proc newFileStream*(f: TFile): PFileStream =
## creates a new stream from the file `f`. ## creates a new stream from the file `f`.
new(result) new(result)
result.f = f result.f = f
@ -272,7 +274,7 @@ proc newFileStream*(f: TFile): PFileStream =
result.writeDataImpl = fsWriteData result.writeDataImpl = fsWriteData
result.flushImpl = fsFlush result.flushImpl = fsFlush
proc newFileStream*(filename: string, mode: TFileMode): PFileStream = proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
## creates a new stream from the file named `filename` with the mode `mode`. ## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, nil is returned. See the `system ## If the file cannot be opened, nil is returned. See the `system
## <system.html>`_ module for a list of available TFileMode enums. ## <system.html>`_ module for a list of available TFileMode enums.

View file

@ -264,6 +264,19 @@ iterator split*(s: string, sep: char): string =
yield substr(s, first, last-1) yield substr(s, first, last-1)
inc(last) inc(last)
iterator split*(s: string, sep: string): string =
## Splits the string `s` into substrings using a string separator.
##
## Substrings are separated by the string `sep`.
var last = 0
if len(s) > 0:
while last <= len(s):
var first = last
while last < len(s) and s.substr(last, last + <sep.len) != sep:
inc(last)
yield substr(s, first, last-1)
inc(last, sep.len)
iterator splitLines*(s: string): string = iterator splitLines*(s: string): string =
## Splits the string `s` into its containing lines. Every newline ## Splits the string `s` into its containing lines. Every newline
## combination (CR, LF, CR-LF) is supported. The result strings contain ## combination (CR, LF, CR-LF) is supported. The result strings contain
@ -329,6 +342,13 @@ proc split*(s: string, sep: char): seq[string] {.noSideEffect,
## of substrings. ## of substrings.
accumulateResult(split(s, sep)) accumulateResult(split(s, sep))
proc split*(s: string, sep: string): seq[string] {.noSideEffect,
rtl, extern: "nsuSplitString".} =
## Splits the string `s` into substrings using a string separator.
##
## Substrings are separated by the string `sep`.
accumulateResult(split(s, sep))
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect, proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
rtl, extern: "nsuToHex".} = rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation. The resulting string ## Converts `x` to its hexadecimal representation. The resulting string

View file

@ -12,7 +12,7 @@ when defined(nodejs):
else: else:
proc alert*(s: cstring) {.importc, nodecl.} proc alert*(s: cstring) {.importc, nodecl.}
proc log*(s: cstring) {.importc: "console.log", nodecl.} proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
type type
PSafePoint = ptr TSafePoint PSafePoint = ptr TSafePoint
@ -27,11 +27,19 @@ type
line: int # current line number line: int # current line number
filename: cstring filename: cstring
PJSError = ref object
columnNumber {.importc.}: int
fileName {.importc.}: cstring
lineNumber {.importc.}: int
message {.importc.}: cstring
stack {.importc.}: cstring
var var
framePtr {.importc, nodecl, volatile.}: PCallFrame framePtr {.importc, nodecl, volatile.}: PCallFrame
excHandler {.importc, nodecl, volatile.}: PSafePoint = nil excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
# list of exception handlers # list of exception handlers
# a global variable for the root of all try blocks # a global variable for the root of all try blocks
lastJSError {.importc, nodecl, volatile.}: PJSError = nil
{.push stacktrace: off, profiler:off.} {.push stacktrace: off, profiler:off.}
proc nimBoolToStr(x: bool): string {.compilerproc.} = proc nimBoolToStr(x: bool): string {.compilerproc.} =
@ -43,7 +51,11 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
result[0] = x result[0] = x
proc getCurrentExceptionMsg*(): string = proc getCurrentExceptionMsg*(): string =
if excHandler != nil: return $excHandler.exc.msg if excHandler != nil and excHandler.exc != nil:
return $excHandler.exc.msg
elif lastJSError != nil:
return $lastJSError.message
else:
return "" return ""
proc auxWriteStackTrace(f: PCallFrame): string = proc auxWriteStackTrace(f: PCallFrame): string =
@ -77,11 +89,13 @@ proc auxWriteStackTrace(f: PCallFrame): string =
add(result, "\n") add(result, "\n")
proc rawWriteStackTrace(): string = proc rawWriteStackTrace(): string =
if framePtr == nil: if framePtr != nil:
result = "No stack traceback available\n" result = "Traceback (most recent call last)\n" & auxWriteStackTrace(framePtr)
else:
result = "Traceback (most recent call last)\n"& auxWriteStackTrace(framePtr)
framePtr = nil framePtr = nil
elif lastJSError != nil:
result = $lastJSError.stack
else:
result = "No stack traceback available\n"
proc raiseException(e: ref E_Base, ename: cstring) {. proc raiseException(e: ref E_Base, ename: cstring) {.
compilerproc, asmNoStackFrame.} = compilerproc, asmNoStackFrame.} =
@ -472,17 +486,17 @@ proc ze*(a: int): int {.compilerproc.} =
proc ze64*(a: int64): int64 {.compilerproc.} = proc ze64*(a: int64): int64 {.compilerproc.} =
result = a result = a
proc ToU8(a: int): int8 {.asmNoStackFrame, compilerproc.} = proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} =
asm """ asm """
return `a`; return `a`;
""" """
proc ToU16(a: int): int16 {.asmNoStackFrame, compilerproc.} = proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} =
asm """ asm """
return `a`; return `a`;
""" """
proc ToU32(a: int): int32 {.asmNoStackFrame, compilerproc.} = proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
asm """ asm """
return `a`; return `a`;
""" """
@ -503,17 +517,17 @@ proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} = proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
case n.kind case n.kind
of nkNone: sysAssert(false, "NimCopyAux") of nkNone: sysAssert(false, "nimCopyAux")
of nkSlot: of nkSlot:
asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);" asm "`dest`[`n`.offset] = nimCopy(`src`[`n`.offset], `n`.typ);"
of nkList: of nkList:
for i in 0..n.len-1: for i in 0..n.len-1:
NimCopyAux(dest, src, n.sons[i]) nimCopyAux(dest, src, n.sons[i])
of nkCase: of nkCase:
asm """ asm """
`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ); `dest`[`n`.offset] = nimCopy(`src`[`n`.offset], `n`.typ);
for (var i = 0; i < `n`.sons.length; ++i) { for (var i = 0; i < `n`.sons.length; ++i) {
NimCopyAux(`dest`, `src`, `n`.sons[i][1]); nimCopyAux(`dest`, `src`, `n`.sons[i][1]);
} }
""" """
@ -534,17 +548,17 @@ proc nimCopy(x: pointer, ti: PNimType): pointer =
for (var key in `x`) { `result`[key] = `x`[key]; } for (var key in `x`) { `result`[key] = `x`[key]; }
""" """
of tyTuple, tyObject: of tyTuple, tyObject:
if ti.base != nil: result = NimCopy(x, ti.base) if ti.base != nil: result = nimCopy(x, ti.base)
elif ti.kind == tyObject: elif ti.kind == tyObject:
asm "`result` = {m_type: `ti`};" asm "`result` = {m_type: `ti`};"
else: else:
asm "`result` = {};" asm "`result` = {};"
NimCopyAux(result, x, ti.node) nimCopyAux(result, x, ti.node)
of tySequence, tyArrayConstr, tyOpenArray, tyArray: of tySequence, tyArrayConstr, tyOpenArray, tyArray:
asm """ asm """
`result` = new Array(`x`.length); `result` = new Array(`x`.length);
for (var i = 0; i < `x`.length; ++i) { for (var i = 0; i < `x`.length; ++i) {
`result`[i] = NimCopy(`x`[i], `ti`.base); `result`[i] = nimCopy(`x`[i], `ti`.base);
} }
""" """
of tyString: of tyString:
@ -584,12 +598,12 @@ proc genericReset(x: Pointer, ti: PNimType): pointer {.compilerproc.} =
else: else:
result = nil result = nil
proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {. proc arrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
asmNoStackFrame, compilerproc.} = asmNoStackFrame, compilerproc.} =
# types are fake # types are fake
asm """ asm """
var result = new Array(`len`); var result = new Array(`len`);
for (var i = 0; i < `len`; ++i) result[i] = NimCopy(`value`, `typ`); for (var i = 0; i < `len`; ++i) result[i] = nimCopy(`value`, `typ`);
return result; return result;
""" """

View file

@ -348,6 +348,10 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
generateRss(destFilename, parseNewsTitles(srcFilename)) generateRss(destFilename, parseNewsTitles(srcFilename))
proc buildJS(destPath: string) =
exec("nimrod js -d:release --out:$1 web/babelpkglist.nim" %
[destPath / "babelpkglist.js"])
proc main(c: var TConfigData) = proc main(c: var TConfigData) =
const const
cmd = "nimrod rst2html --compileonly $1 -o:web/$2.temp web/$2.txt" cmd = "nimrod rst2html --compileonly $1 -o:web/$2.temp web/$2.txt"
@ -377,6 +381,7 @@ proc main(c: var TConfigData) =
quit("[Error] cannot write file: " & outfile) quit("[Error] cannot write file: " & outfile)
removeFile(temp) removeFile(temp)
copyDir("web/assets", "web/upload/assets") copyDir("web/assets", "web/upload/assets")
buildJS("web/upload")
buildNewsRss(c, "web/upload") buildNewsRss(c, "web/upload")
buildAddDoc(c, "web/upload") buildAddDoc(c, "web/upload")
buildDocSamples(c, "web/upload") buildDocSamples(c, "web/upload")

72
web/babelpkglist.nim Normal file
View file

@ -0,0 +1,72 @@
import base64, strutils, json, htmlgen, dom, algorithm
type
TData = object
content {.importc.}: cstring
proc decodeContent(content: string): string =
result = ""
for line in content.splitLines:
if line != "":
result.add decode(line)
proc contains(x: seq[PJSonNode], s: string): bool =
for i in x:
assert i.kind == JString
if i.str == s: return true
proc processContent(content: string) =
var jsonDoc = parseJson(content)
assert jsonDoc.kind == JArray
var jsonArr = jsonDoc.elems
jsonArr.sort do (x, y: PJsonNode) -> int:
system.cmp(x["name"].str, y["name"].str)
var
officialList = ""
officialCount = 0
unofficialList = ""
unofficialCount = 0
for pkg in jsonArr:
assert pkg.kind == JObject
let pkgWeb =
if pkg.hasKey("web"): pkg["web"].str
else: pkg["url"].str
let listItem = li(a(href=pkgWeb, pkg["name"].str), " ", pkg["description"].str)
if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
"official" in pkg["tags"].elems:
officialCount.inc
officialList.add listItem & "\n"
else:
unofficialCount.inc
unofficialList.add listItem & "\n"
var officialPkgListDiv = document.getElementById("officialPkgList")
officialPkgListDiv.innerHTML.add(
p("There are currently " & $officialCount &
" official packages in the Babel package repository.") &
ul(officialList)
)
var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
unofficialPkgListDiv.innerHTML.add(
p("There are currently " & $unofficialCount &
" unofficial packages in the Babel package repository.") &
ul(unofficialList)
)
proc gotPackageList(apiReply: TData) {.exportc.} =
let decoded = decodeContent($apiReply.content)
try:
processContent(decoded)
except:
var officialPkgListDiv = document.getElementById("officialPkgList")
var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
let msg = p("Unable to retrieve package list: ",
code(getCurrentExceptionMsg()))
officialPkgListDiv.innerHTML = msg
unofficialPkgListDiv.innerHTML = msg