diff --git a/preserves.nimble b/preserves.nimble index f3ba7ed..5feeecd 100644 --- a/preserves.nimble +++ b/preserves.nimble @@ -1,6 +1,6 @@ # Package -version = "3.0.1" # versioned in git, this version is just to confuse nimble +version = "3.1.0" # versioned in git, this version is just to confuse nimble author = "Emery Hemingway" description = "data model and serialization format" license = "Unlicense" diff --git a/src/preserves.nim b/src/preserves.nim index db5f20c..4a1f54a 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -23,6 +23,13 @@ const atomKinds* = {pkBoolean, pkFloat, pkDouble, pkSignedInteger, pkString, pkByteString, pkSymbol} compoundKinds* = {pkRecord, pkSequence, pkSet, pkDictionary} +type Symbol* = distinct string +proc `$`*(s: Symbol): string {.borrow.} +proc `<`*(x, y: Symbol): bool {.borrow.} +proc `==`*(x, y: Symbol): bool {.borrow.} +proc len*(s: Symbol): int {.borrow.} +proc hash*(s: Symbol): Hash {.borrow.} + type Preserve*[E = void] = object case kind*: PreserveKind @@ -39,7 +46,7 @@ type of pkByteString: bytes*: seq[byte] of pkSymbol: - symbol*: string + symbol*: Symbol of pkRecord: record*: seq[Preserve[E]] # label is last of pkSequence: @@ -175,7 +182,7 @@ proc hash*(pr: Preserve): Hash = of pkByteString: h = h !& hash(pr.bytes) of pkSymbol: - h = h !& hash(pr.symbol) + h = h !& hash(string pr.symbol) of pkRecord: for val in pr.record: h = h !& hash(val) @@ -262,7 +269,7 @@ proc `[]=`*(pr: var Preserve; key, val: Preserve) = proc toSymbol*(s: sink string; E = void): Preserve[E] {.inline.} = ## Create a Preserves symbol value. - Preserve[E](kind: pkSymbol, symbol: s) + Preserve[E](kind: pkSymbol, symbol: Symbol s) proc initRecord*[E](label: Preserve[E]; arity: Natural = 0): Preserve[E] = ## Create a Preserves record value. @@ -358,9 +365,9 @@ func isByteString*(pr: Preserve): bool {.inline.} = pr.kind == pkByteString func isSymbol*(pr: Preserve): bool {.inline.} = pr.kind == pkSymbol ## Check if `pr` is a Preserves symbol. -func isSymbol*(pr: Preserve; sym: string): bool {.inline.} = +func isSymbol*(pr: Preserve; sym: string|Symbol): bool {.inline.} = ## Check if ``pr`` is a Preserves symbol of ``sym``. - (pr.kind == pkSymbol) and (pr.symbol == sym) + (pr.kind == pkSymbol) and (pr.symbol == Symbol(sym)) func isRecord*(pr: Preserve): bool {.inline.} = (pr.kind == pkRecord) and (pr.record.len > 0) ## Check if ``pr`` is a Preserves record. @@ -474,7 +481,7 @@ proc write*[E](str: Stream; pr: Preserve[E]) = of pkSymbol: str.write(0xb3'u8) str.writeVarint(pr.symbol.len) - str.write(pr.symbol) + str.write(string pr.symbol) of pkRecord: assert(pr.record.len > 0) str.write(0xb4'u8) @@ -547,7 +554,7 @@ proc decodePreserves*(s: Stream; E = void): Preserve[E] = result.bytes = cast[seq[byte]](s.readStr(len)) of 0xb3: let len = s.readVarint() - result = Preserve[E](kind: pkSymbol, symbol: s.readStr(len)) + result = Preserve[E](kind: pkSymbol, symbol: Symbol s.readStr(len)) of 0xb4: result = Preserve[E](kind: pkRecord) var label = decodePreserves(s, E) @@ -618,10 +625,6 @@ template preservesDictionary*() {.pragma.} ## Serialize this object or tuple as a dictionary. ## See ``toPreserve``. -template preservesSymbol*() {.pragma.} - ## Serialize this string as a symbol. - ## See ``toPreserve``. - template preservesOr*() {.pragma.} ## Serialize this object as an ``or`` alternative. ## See ``toPreserve``. @@ -648,8 +651,6 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] = elif T is E: result = embed(x) elif compiles(toPreserveHook(x, E)): result = toPreserveHook(x, E) - elif T is distinct: - result = toPreserve(x.distinctBase, E) elif T is enum: result = toSymbol($x, E) elif T is seq[byte]: @@ -677,11 +678,13 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] = result = Preserve[E](kind: pkString, string: x) elif T is SomeInteger: result = Preserve[E](kind: pkSignedInteger, int: x.BiggestInt) + elif T is Symbol: + result = Preserve[E](kind: pkSymbol, symbol: x) + elif T is distinct: + result = toPreserve(x.distinctBase, E) elif T is object: template fieldToPreserve(key: string; val: typed): Preserve {.used.} = - when x.dot(key).hasCustomPragma(preservesSymbol): - toSymbol(val, E) - elif x.dot(key).hasCustomPragma(preservesLiteral): + when x.dot(key).hasCustomPragma(preservesLiteral): const lit = parsePreserves(x.dot(key).getCustomPragmaVal(preservesLiteral)) cast[Preserve[E]](lit) else: @@ -747,10 +750,7 @@ proc toPreserveHook*[A, B](table: Table[A, B]|TableRef[A, B], E: typedesc): Pres ## Hook for preserving ``Table``. result = initDictionary[E]() for k, v in table.pairs: - when A is string: - result[toPreserve(k, E)] = toPreserve(v, E) - else: - result[toPreserve(k, E)] = toPreserve(v, E) + result[toPreserve(k, E)] = toPreserve(v, E) proc fromPreserve*[T, E](v: var T; pr: Preserve[E]): bool = ## Inplace version of `preserveTo`. Returns ``true`` on @@ -779,12 +779,10 @@ proc fromPreserve*[T, E](v: var T; pr: Preserve[E]): bool = result = true elif compiles(fromPreserveHook(v, pr)): result = fromPreserveHook(v, pr) - elif T is distinct: - result = fromPreserve(v.distinctBase, pr) elif T is enum: if pr.isSymbol: try: - v = parseEnum[T](pr.symbol) + v = parseEnum[T](string pr.symbol) result = true except ValueError: discard elif T is bool: @@ -830,9 +828,16 @@ proc fromPreserve*[T, E](v: var T; pr: Preserve[E]): bool = v = pr.string result = true of pkSymbol: - v = pr.symbol + # loose convertability of Preserves symbol to Nim string + v = string pr.symbol result = true else: discard + elif T is Symbol: + if pr.kind == pkSymbol: + v = pr.symbol + result = true + elif T is distinct: + result = fromPreserve(v.distinctBase, pr) elif T is tuple: case pr.kind of pkRecord, pkSequence: @@ -855,12 +860,7 @@ proc fromPreserve*[T, E](v: var T; pr: Preserve[E]): bool = result = fromPreserve(v[], pr) elif T is object: template fieldFromPreserve(key: string; val: typed; pr: Preserve[E]): bool {.used.} = - when v.dot(key).hasCustomPragma(preservesSymbol): - if pr.isSymbol: - fromPreserve(val, pr) - else: - false - elif v.dot(key).hasCustomPragma(preservesLiteral): + when v.dot(key).hasCustomPragma(preservesLiteral): const lit = parsePreserves(v.dot(key).getCustomPragmaVal(preservesLiteral)) pr == lit else: @@ -1057,7 +1057,7 @@ proc concat[E](result: var string; pr: Preserve[E]) = result.add(alphabet[int(b and 0xf)]) result.add('"') of pkSymbol: - result.add(escapeJsonUnquoted(pr.symbol)) + result.add(escapeJsonUnquoted(string pr.symbol)) of pkRecord: assert(pr.record.len > 0) result.add('<') diff --git a/src/preserves/jsonhooks.nim b/src/preserves/jsonhooks.nim index 9abb70e..d13df0f 100644 --- a/src/preserves/jsonhooks.nim +++ b/src/preserves/jsonhooks.nim @@ -41,7 +41,7 @@ proc fromPreserveHook*[E](js: var JsonNode; prs: Preserve[E]): bool = of pkString: js = newJString(prs.string) of pkSymbol: - case prs.symbol + case prs.symbol.string of "false": js = newJBool(false) of "true": diff --git a/src/preserves/parse.nim b/src/preserves/parse.nim index cf91b2d..b368c04 100644 --- a/src/preserves/parse.nim +++ b/src/preserves/parse.nim @@ -87,7 +87,7 @@ proc parsePreserves*(text: string): Preserve[void] {.gcsafe.} = pushStack Value(kind: pkByteString, bytes: cast[seq[byte]](base64.decode($1))) Preserves.Symbol <- Preserves.Symbol: - pushStack Value(kind: pkSymbol, symbol: $0) + pushStack Value(kind: pkSymbol, symbol: Symbol $0) Preserves.Embedded <- Preserves.Embedded: var v = stack.pop.value diff --git a/src/preserves/preserves_schema_nim.nim b/src/preserves/preserves_schema_nim.nim index 6290977..586d3d5 100644 --- a/src/preserves/preserves_schema_nim.nim +++ b/src/preserves/preserves_schema_nim.nim @@ -88,14 +88,14 @@ proc ident(pat: Pattern; fallback = string): PNode = proc ident(np: NamedPattern; fallback: string): PNode = case np.orKind of NamedPatternKind.`named`: - ident(np.named.name) + ident(string np.named.name) of NamedPatternKind.`anonymous`: ident(fallback) proc ident(np: NamedSimplePattern; fallback: string): PNode = case np.orKind of NamedSimplePatternKind.`named`: - ident(np.named.name) + ident(string np.named.name) of NamedSimplePatternKind.`anonymous`: ident(fallback) @@ -120,8 +120,8 @@ proc dotExtend(result: var PNode; label: string) = else: result = nn(nkDotExpr, result, id) proc ident(`ref`: Ref): PNode = - for m in`ref`.module: dotExtend(result, m) - dotExtend(result, `ref`.name.capitalizeAscii) + for m in`ref`.module: dotExtend(result, string m) + dotExtend(result, `ref`.name.string.capitalizeAscii) proc deref(scm: Schema; r: Ref): Definition = assert r.module == @[] @@ -284,7 +284,7 @@ proc typeIdent(atom: AtomKind): PNode = of AtomKind.`Signedinteger`: ident"int" of AtomKind.`String`: ident"string" of AtomKind.`Bytestring`: nn(nkBracketExpr, ident"seq", ident"byte") - of AtomKind.`Symbol`: ident"string" + of AtomKind.`Symbol`: ident"Symbol" proc typeIdent(scm: Schema; sp: SimplePattern): TypeSpec = case sp.orKind @@ -362,7 +362,7 @@ proc label(pat: Pattern): string = proc label(na: NamedPattern): string = case na.orKind of NamedPatternKind.`named`: - na.named.name + string na.named.name of NamedPatternKind.`anonymous`: "data" # TODO @@ -372,7 +372,7 @@ proc idStr(sp: SimplePattern): string = of pkString: result = sp.lit.value.string of pkSymbol: - result = sp.lit.value.symbol + result = string sp.lit.value.symbol else: discard doAssert(result != "", "no idStr for " & $sp) @@ -383,7 +383,7 @@ proc idStr(pat: Pattern): string = proc idStr(np: NamedPattern): string = case np.orKind of NamedPatternKind.`named`: - np.named.name + string np.named.name of NamedPatternKind.`anonymous`: np.anonymous.idStr @@ -449,11 +449,6 @@ proc addField(recList: PNode; scm: Schema; known: var TypeTable; sp: SimplePatte ident"preservesLiteral", toStrLit(scm, sp)))) recList.add identDef(id, (ident"bool", false)) - elif sp.orKind == SimplePatternKind.`atom` and - sp.atom.atomKind == AtomKind.Symbol: - let id = nn(nkPragmaExpr, - id, nn(nkPragma, ident"preservesSymbol")) - recList.add identDef(id, (ident"string", false)) else: recList.add identDef(id, nimTypeOf(scm, known, sp)) @@ -501,14 +496,14 @@ proc addFields(recList: PNode; scm: Schema; known: var TypeTable; pat: Pattern; proc addFields(recList: PNode; scm: Schema; known: var TypeTable; entries: DictionaryEntries; parentName: string): PNode {.discardable.} = for key, val in entries.pairs: doAssert(key.isSymbol) - let label = key.symbol + let label = string key.symbol addField(recList, scm, known, val.pattern, label) recList proc nimTypeOf(scm: Schema; known: var TypeTable; nsp: NamedSimplePattern; name: string): TypeSpec = case nsp.orKind of NamedsimplepatternKind.named: - nimTypeOf(scm, known, nsp.named.pattern, nsp.named.name) + nimTypeOf(scm, known, nsp.named.pattern, string nsp.named.name) of NamedsimplepatternKind.anonymous: nimTypeOf(scm, known, nsp.anonymous, name) @@ -628,7 +623,7 @@ proc literalToPreserveCall(scm: Schema; pr: Preserve): PNode = of pkByteString: return nn(nkCall, ident"parsePreserves", newStrNode(nkTripleStrLit, $pr)) of pkSymbol: - constr($pr.orKind, "symbol", newStrNode(nkStrLit, pr.symbol)) + constr($pr.orKind, "symbol", newStrNode(nkStrLit, string pr.symbol)) else: raise newException(ValueError, "refusing to convert to a literal: " & $pr) prConstr @@ -647,7 +642,7 @@ proc collectRefImports(imports: PNode; sp: SimplePattern) = imports.add ident"std/tables" of SimplePatternKind.Ref: if sp.`ref`.module != @[]: - imports.add ident(sp.ref.module[0]) + imports.add ident(string sp.ref.module[0]) else: discard proc collectRefImports(imports: PNode; cp: CompoundPattern) = @@ -702,9 +697,9 @@ proc renderNimModule*(scm: Schema): string = unembeddableType, embeddableType: PNode for name, def in scm.data.definitions.pairs: if isLiteral(scm, def): - generateConstProcs(procs, scm, name, def) + generateConstProcs(procs, scm, string name, def) else: - var name = name + var name = string name name[0] = name[0].toUpperAscii var defIdent = parameterize(ident(name), isEmbeddable(scm, def)) if not isSymbolEnum(scm, def) and not isAny(scm, def): @@ -826,7 +821,7 @@ when isMainModule: preserveTo(pr, Bundle).map do (bundle: Bundle): useful = true for modPath, scm in bundle.modules: - let path = joinPath(modPath) & ".nim" + let path = joinPath(cast[seq[string]](modPath)) & ".nim" writeModule(scm, path) else: let diff --git a/src/preserves/schema.nim b/src/preserves/schema.nim index babccba..ccef6e4 100644 --- a/src/preserves/schema.nim +++ b/src/preserves/schema.nim @@ -4,9 +4,9 @@ import ../preserves, std/typetraits, std/tables type Ref* {.preservesRecord: "ref".} = object `module`*: ModulePath - `name`* {.preservesSymbol.}: string + `name`*: Symbol - ModulePath* = seq[string] + ModulePath* = seq[Symbol] Bundle*[E] {.preservesRecord: "bundle".} = ref object `modules`*: Modules[E] @@ -55,7 +55,7 @@ type `AtomKind`* {.preservesOr, pure.} = enum `Boolean`, `Float`, `Double`, `SignedInteger`, `String`, `ByteString`, `Symbol` - Definitions*[E] = Table[string, Definition[E]] + Definitions*[E] = Table[Symbol, Definition[E]] DictionaryEntries*[E] = Table[Preserve[E], NamedSimplePattern[E]] NamedPatternKind* {.pure.} = enum `named`, `anonymous` @@ -181,7 +181,7 @@ type Binding*[E] {.preservesRecord: "named".} = ref object - `name`* {.preservesSymbol.}: string + `name`*: Symbol `pattern`*: SimplePattern[E] proc `$`*[E](x: Bundle[E] | CompoundPattern[E] | Modules[E] | Definitions[E] | diff --git a/src/preserves/schemaparse.nim b/src/preserves/schemaparse.nim index cd70a68..cb01c4d 100644 --- a/src/preserves/schemaparse.nim +++ b/src/preserves/schemaparse.nim @@ -86,14 +86,14 @@ const parser = peg("Schema", p: ParseState): p.schema = move ip.schema Definition <- >id * S * '=' * S * (OrPattern | AndPattern | Pattern): - if p.schema.definitions.hasKey $1: + if p.schema.definitions.hasKey(Symbol $1): raise newException(ValueError, "duplicate definition of " & $1) var node = popStack() def: Definition if not fromPreserve(def, node): raise newException(ValueError, $1 & ": " & $node) - p.schema.definitions[$1] = def + p.schema.definitions[Symbol $1] = def p.stack.setLen(0) OrPattern <- ?('/' * S) * AltPattern * +(S * '/' * S * AltPattern): diff --git a/src/preserves/xmlhooks.nim b/src/preserves/xmlhooks.nim index 0655fa1..2f24367 100644 --- a/src/preserves/xmlhooks.nim +++ b/src/preserves/xmlhooks.nim @@ -52,11 +52,11 @@ proc fromPreserveHook*[E](xn: var XmlNode; pr: Preserve[E]): bool = result = false break if result: - xn = newXmlTree(pr[0].symbol, children, attrs) + xn = newXmlTree(string pr[0].symbol, children, attrs) of pkRecord: if pr.len == 1 and pr[0].isString and pr.label.isSymbol: result = true - case pr.label.symbol: + case pr.label.symbol.string: of "verbatim": xn = newVerbatimText(pr[0].string) of "comment":