Skip to content

Commit 37a16ee

Browse files
authored
encode/decode WKT-CRS string tokens (#8)
1 parent f892f04 commit 37a16ee

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

src/ParseUnparseWKTCRS.jl

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module ParseUnparseWKTCRS
2-
export GrammarSymbolKinds, ParserIdents
2+
export GrammarSymbolKinds, TokenUtil, ParserIdents
33
module GrammarSymbolKinds
44
export GrammarSymbolKind, grammar_symbol_error_kinds
55
using ParseUnparse.KindConstruction
@@ -47,7 +47,7 @@ module ParseUnparseWKTCRS
4747
)
4848
end
4949
module TokenIterators
50-
export TokenIterator
50+
export TokenIterator, encode_string, decode_string
5151
using ParseUnparse.LexingUtil, ..GrammarSymbolKinds
5252
struct TokenIterator{ListDelimiters, T}
5353
character_iterator::T
@@ -342,6 +342,99 @@ module ParseUnparseWKTCRS
342342
end
343343
end
344344
end
345+
function encode_string_single_char(out::IO, decoded::AbstractChar)
346+
q = only(significant_characters.general.double_quote)
347+
print(out, decoded)
348+
if decoded == q
349+
print(out, decoded)
350+
end
351+
end
352+
function encode_string_no_quotes(out::IO, decoded)
353+
foreach(Base.Fix1(encode_string_single_char, out), decoded)
354+
end
355+
"""
356+
encode_string(out::IO, decoded)::Nothing
357+
358+
Encode the `decoded` iterator as a WKT-CRS string, outputting to `out`.
359+
"""
360+
function encode_string(out::IO, decoded)
361+
q = only(significant_characters.general.double_quote)
362+
print(out, q)
363+
encode_string_no_quotes(out, decoded)
364+
print(out, q)
365+
nothing
366+
end
367+
"""
368+
decode_string(out::IO, encoded)::Bool
369+
370+
Decode the `encoded` iterator, interpreted as a WKT-CRS string, outputting to `out`.
371+
372+
Return `true` if and only if no error was encountered.
373+
"""
374+
function decode_string(out::IO, encoded)
375+
lexer_state = let ols = lexer_state_simple_new(encoded)
376+
if ols === ()
377+
return false
378+
end
379+
only(ols)
380+
end
381+
dquot = significant_characters.general.double_quote
382+
# This is a finite-state machine just like in `lex_string!`, but starting
383+
# with an extra state to skip initial white space and ending with an extra
384+
# state to check there's nothing except for white space at the end.
385+
while true
386+
oc = lexer_state_consume!(lexer_state)
387+
if isempty(oc)
388+
return false
389+
end
390+
c = only(oc)
391+
if c dquot
392+
break
393+
end
394+
if c significant_characters.general.whitespace
395+
return false
396+
end
397+
end
398+
# state 1 is merged into the above
399+
@label state_2
400+
let oc = lexer_state_consume!(lexer_state)
401+
if isempty(oc)
402+
return false
403+
end
404+
c = only(oc)
405+
if character_does_not_need_escaping(c)
406+
print(out, c)
407+
@goto state_2
408+
end
409+
end
410+
# state 3, accepting state
411+
let oc = lexer_state_peek!(lexer_state)
412+
if isempty(oc)
413+
return true
414+
end
415+
c = only(oc)
416+
if !character_does_not_need_escaping(c)
417+
print(out, c)
418+
lexer_state_consume!(lexer_state)
419+
@goto state_2
420+
end
421+
end
422+
# trailing whitespace
423+
while true
424+
oc = lexer_state_consume!(lexer_state)
425+
if isempty(oc)
426+
break
427+
end
428+
if only(oc) significant_characters.general.whitespace
429+
return false
430+
end
431+
end
432+
true
433+
end
434+
end
435+
module TokenUtil
436+
export encode_string, decode_string
437+
using ..TokenIterators
345438
end
346439
module ParserIdents
347440
export ParserIdent

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Test
22

33
@testset "ParseUnparseWKTCRS.jl" begin
4+
include("runtests_token_util.jl")
45
include("runtests_parser_idents.jl")
56
include("runtests_aqua.jl")
67
end

test/runtests_token_util.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module TestTokenUtil
2+
using ParseUnparseWKTCRS.TokenUtil, Test
3+
@testset "`TokenUtil`" begin
4+
@test "z" == (@inferred sprint(decode_string, """ "z" """))::AbstractString
5+
@test '"'^2 == (@inferred sprint(encode_string, ""))::AbstractString
6+
@test '"'^4 == (@inferred sprint(encode_string, "\""))::AbstractString
7+
for s ("", " ", "z", " z", "z ", " z ", "\"", "\"\"", "\"z\"")
8+
@test s == sprint(decode_string, sprint(encode_string, s))
9+
end
10+
end
11+
end

0 commit comments

Comments
 (0)