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

@ -861,26 +861,97 @@ proc parseJson(p: var TJsonParser): PJsonNode =
of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof:
raiseParseErr(p, "{")
proc parseJson*(s: PStream, filename: string): PJsonNode =
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
## for nice error messages.
var p: TJsonParser
p.open(s, filename)
discard getTok(p) # read first token
result = p.parseJson()
p.close()
when not defined(js):
proc parseJson*(s: PStream, filename: string): PJsonNode =
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
## for nice error messages.
var p: TJsonParser
p.open(s, filename)
discard getTok(p) # read first token
result = p.parseJson()
p.close()
proc parseJson*(buffer: string): PJsonNode =
## Parses JSON from `buffer`.
result = parseJson(newStringStream(buffer), "input")
proc parseJson*(buffer: string): PJsonNode =
## Parses JSON from `buffer`.
result = parseJson(newStringStream(buffer), "input")
proc parseFile*(filename: string): PJsonNode =
## Parses `file` into a `PJsonNode`.
var stream = newFileStream(filename, fmRead)
if stream == nil:
raise newException(EIO, "cannot read from file: " & 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()
proc parseFile*(filename: string): PJsonNode =
## Parses `file` into a `PJsonNode`.
var stream = newFileStream(filename, fmRead)
if stream == nil:
raise newException(EIO, "cannot read from file: " & filename)
result = parseJson(stream, filename)
when false:
import os
var s = newFileStream(ParamStr(1), fmRead)

View file

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

View file

@ -239,45 +239,47 @@ proc newStringStream*(s: string = ""): PStringStream =
result.readDataImpl = ssReadData
result.writeDataImpl = ssWriteData
type
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
TFileStream* = object of TStream
f: TFile
when not defined(js):
proc fsClose(s: PStream) =
if PFileStream(s).f != nil:
close(PFileStream(s).f)
PFileStream(s).f = nil
proc fsFlush(s: PStream) = flushFile(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 fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
type
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
TFileStream* = object of TStream
f: TFile
proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
result = readBuffer(PFileStream(s).f, buffer, bufLen)
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream")
proc fsClose(s: PStream) =
if PFileStream(s).f != nil:
close(PFileStream(s).f)
PFileStream(s).f = nil
proc fsFlush(s: PStream) = flushFile(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 fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
proc newFileStream*(f: TFile): PFileStream =
## creates a new stream from the file `f`.
new(result)
result.f = f
result.closeImpl = fsClose
result.atEndImpl = fsAtEnd
result.setPositionImpl = fsSetPosition
result.getPositionImpl = fsGetPosition
result.readDataImpl = fsReadData
result.writeDataImpl = fsWriteData
result.flushImpl = fsFlush
proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
result = readBuffer(PFileStream(s).f, buffer, bufLen)
proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
## 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
## <system.html>`_ module for a list of available TFileMode enums.
var f: TFile
if open(f, filename, mode): result = newFileStream(f)
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream")
proc newFileStream*(f: TFile): PFileStream =
## creates a new stream from the file `f`.
new(result)
result.f = f
result.closeImpl = fsClose
result.atEndImpl = fsAtEnd
result.setPositionImpl = fsSetPosition
result.getPositionImpl = fsGetPosition
result.readDataImpl = fsReadData
result.writeDataImpl = fsWriteData
result.flushImpl = fsFlush
proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
## 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
## <system.html>`_ module for a list of available TFileMode enums.
var f: TFile
if open(f, filename, mode): result = newFileStream(f)
when true:

View file

@ -264,6 +264,19 @@ iterator split*(s: string, sep: char): string =
yield substr(s, first, last-1)
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 =
## Splits the string `s` into its containing lines. Every newline
## 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.
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,
rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation. The resulting string