|
| 1 | +__precompile__(true) |
| 2 | +"""" |
| 3 | +Add C, Python and type-based formatting to Str string literals |
| 4 | +
|
| 5 | +Copyright 2016-2018 Gandalf Software, Inc., Scott P. Jones |
| 6 | +Licensed under MIT License, see LICENSE.md |
| 7 | +""" |
| 8 | +module StrFormat |
| 9 | + |
| 10 | +using Format, StrLiterals |
| 11 | + |
| 12 | +parse_error(s) = throw(StrLiterals._ParseError(s)) |
| 13 | + |
| 14 | +_check_exp(ex) = |
| 15 | + isa(ex, Expr) && (ex.head === :continue) && parse_error("Incomplete expression") |
| 16 | + |
| 17 | +function _parse_format(str, pos, fun) |
| 18 | + ex, j = StrLiterals._parse(str, pos; greedy=false) |
| 19 | + _check_exp(ex) |
| 20 | + ex, k = StrLiterals._parse(string("a", str[pos:j-1]), 1, greedy=true) |
| 21 | + _check_exp(ex) |
| 22 | + isa(ex, Symbol) && (println(string("a", str[pos:j-1])) ; dump(ex)) |
| 23 | + ex.args[1] = fun |
| 24 | + ex, j |
| 25 | +end |
| 26 | + |
| 27 | +function _parse_fmt(sx::Vector{Any}, s::AbstractString, unescape::Function, |
| 28 | + i::Integer, j::Integer, k::Integer) |
| 29 | + # Move past \\, k should point to '%' |
| 30 | + c, k = next(s, k) |
| 31 | + done(s, k) && parse_error("Incomplete % expression") |
| 32 | + # Handle interpolation |
| 33 | + isempty(s[i:j-1]) || push!(sx, unescape(s[i:j-1])) |
| 34 | + if s[k] == '(' |
| 35 | + # Need to find end to parse to |
| 36 | + ex, j = _parse_format(s, k, Format.fmt) |
| 37 | + else |
| 38 | + # Move past %, c should point to letter |
| 39 | + beg = k |
| 40 | + while true |
| 41 | + c, k = next(s, k) |
| 42 | + done(s, k) && parse_error("Incomplete % expression") |
| 43 | + s[k] == '(' && break |
| 44 | + end |
| 45 | + ex, j = _parse_format(s, k, Format.cfmt) |
| 46 | + insert!(ex.args, 2, s[beg-1:k-1]) |
| 47 | + end |
| 48 | + push!(sx, esc(ex)) |
| 49 | + j |
| 50 | +end |
| 51 | + |
| 52 | +function _parse_pyfmt(sx::Vector{Any}, s::AbstractString, unescape::Function, |
| 53 | + i::Integer, j::Integer, k::Integer) |
| 54 | + # Move past \\, k should point to '{' |
| 55 | + c, k = next(s, k) |
| 56 | + done(s, k) && parse_error("Incomplete {...} Python format expression") |
| 57 | + # Handle interpolation |
| 58 | + isempty(s[i:j-1]) || push!(sx, unescape(s[i:j-1])) |
| 59 | + beg = k # start location |
| 60 | + c, k = next(s, k) |
| 61 | + while c != '}' |
| 62 | + done(s, k) && parse_error(string("\\{ missing closing } in ", c)) |
| 63 | + c, k = next(s, k) |
| 64 | + end |
| 65 | + done(s, k) && parse_error("Missing (expr) in Python format expression") |
| 66 | + c, k = next(s, k) |
| 67 | + c == '(' || parse_error(string("Missing (expr) in Python format expression: ", c)) |
| 68 | + # Need to find end to parse to |
| 69 | + ex, j = _parse_format(s, k-1, Format.pyfmt) |
| 70 | + insert!(ex.args, 2, s[beg:k-3]) |
| 71 | + push!(sx, esc(ex)) |
| 72 | + j |
| 73 | +end |
| 74 | + |
| 75 | +function __init__() |
| 76 | + StrLiterals.interpolate['%'] = _parse_fmt |
| 77 | + StrLiterals.interpolate['{'] = _parse_pyfmt |
| 78 | +end |
| 79 | + |
| 80 | +end # module StrFormat |
0 commit comments