JS: Fixes math and streams module and implements json.
This commit is contained in:
parent
b0a16fb619
commit
96c97d4103
3 changed files with 128 additions and 55 deletions
|
|
@ -861,26 +861,97 @@ 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):
|
||||||
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
|
proc parseJson*(s: PStream, filename: string): PJsonNode =
|
||||||
## for nice error messages.
|
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
|
||||||
var p: TJsonParser
|
## for nice error messages.
|
||||||
p.open(s, filename)
|
var p: TJsonParser
|
||||||
discard getTok(p) # read first token
|
p.open(s, filename)
|
||||||
result = p.parseJson()
|
discard getTok(p) # read first token
|
||||||
p.close()
|
result = p.parseJson()
|
||||||
|
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 =
|
||||||
|
## 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:
|
when false:
|
||||||
import os
|
import os
|
||||||
var s = newFileStream(ParamStr(1), fmRead)
|
var s = newFileStream(ParamStr(1), fmRead)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -239,45 +239,47 @@ proc newStringStream*(s: string = ""): PStringStream =
|
||||||
result.readDataImpl = ssReadData
|
result.readDataImpl = ssReadData
|
||||||
result.writeDataImpl = ssWriteData
|
result.writeDataImpl = ssWriteData
|
||||||
|
|
||||||
type
|
when not defined(js):
|
||||||
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
|
|
||||||
TFileStream* = object of TStream
|
|
||||||
f: TFile
|
|
||||||
|
|
||||||
proc fsClose(s: PStream) =
|
type
|
||||||
if PFileStream(s).f != nil:
|
PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
|
||||||
close(PFileStream(s).f)
|
TFileStream* = object of TStream
|
||||||
PFileStream(s).f = nil
|
f: TFile
|
||||||
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 fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
|
proc fsClose(s: PStream) =
|
||||||
result = readBuffer(PFileStream(s).f, buffer, bufLen)
|
if PFileStream(s).f != nil:
|
||||||
|
close(PFileStream(s).f)
|
||||||
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
|
PFileStream(s).f = nil
|
||||||
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
|
proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
|
||||||
raise newEIO("cannot write to stream")
|
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 =
|
proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
|
||||||
## creates a new stream from the file `f`.
|
result = readBuffer(PFileStream(s).f, buffer, bufLen)
|
||||||
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 =
|
proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
|
||||||
## creates a new stream from the file named `filename` with the mode `mode`.
|
if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
|
||||||
## If the file cannot be opened, nil is returned. See the `system
|
raise newEIO("cannot write to stream")
|
||||||
## <system.html>`_ module for a list of available TFileMode enums.
|
|
||||||
var f: TFile
|
proc newFileStream*(f: TFile): PFileStream =
|
||||||
if open(f, filename, mode): result = newFileStream(f)
|
## 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:
|
when true:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue