Created
December 17, 2017 01:15
-
-
Save soapdog/ab67db55ec6e7386eb68542d5d3df64b to your computer and use it in GitHub Desktop.
Calculo de rendimento em BTC na Walltime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
Title: "LuiBTC" | |
Author: "Andre Garzia" | |
Needs: 'view | |
] | |
do %json.red | |
view [ | |
title "LuiBTC" | |
style txt: text | |
group-box "Entrada" 1 [ | |
text "Dinheiro investido" investimento: field | |
text "Cotação do dia do investimento" cotacao_dia: field | |
button "Calcular" [ | |
meta_raw: read https://s3.amazonaws.com/data-production-walltime-info/production/dynamic/meta.json | |
meta: load-json meta_raw | |
best_offer: select meta "best_offer" | |
brl_xbt_raw: select best_offer "brl-xbt" | |
brl_xbt: split brl_xbt_raw "/" | |
cotacao_atual/text: form either (length? brl_xbt) > 1 | |
[ (load first brl_xbt) / (load last brl_xbt) ] | |
[ first brl_xbt ] | |
i: load investimento/text | |
cd: load cotacao_dia/text | |
ca: load cotacao_atual/text | |
total_btc/text: form i / cd | |
rendimento/text: form round/to ((ca - cd) * 100 / cd) 0.01 | |
lucro/text: form round/to (i * ((load rendimento/text) / 100)) 0.01 | |
total_real/text: form round/to (i + (load lucro/text)) 0.01 | |
] | |
img: image loose %logo.png | |
] | |
group-box "Resultado" 1 [ | |
text "Cotação atual" cotacao_atual: field | |
text "Total em BTC" total_btc: field | |
text "Rendimento em %" rendimento: field | |
text "Lucro em Real" lucro: field | |
text "Total em Real" total_real: field | |
] | |
];; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
File: %json.red | |
Title: "Red-JSON codec" | |
Purpose: "Convert JSON to Red, and vice versa." | |
Author: "Gregg Irwin" | |
;Date: 09-Sep-2016 | |
Version: 0.0.1 | |
History: { | |
0.0.1 09-Sep-2016 "First release." Gregg | |
} | |
license: [ | |
http://www.apache.org/licenses/LICENSE-2.0 | |
and "The Software shall be used for Good, not Evil." | |
] | |
References: [ | |
http://www.json.org/ | |
https://www.ietf.org/rfc/rfc4627.txt | |
http://www.rfc-editor.org/rfc/rfc7159.txt | |
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf | |
] | |
Notes: { | |
- Ported from %json.r, by Romano Paolo Tenca, Douglas Crockford, and Gregg Irwin. | |
- Further research: JSON libs by Chris Ross-Gill, Kaj de Vos, and @WiseGenius. | |
? Do we want to have a single context or separate encode/decode contexts? | |
? Do we want to use a stack with parse, or recursive load-json/decode calls? | |
- Unicode support is in the works. | |
- Pretty formatting from %json.r removed. Determine what formatting options we want. | |
- Would like to add more detailed decode error info. | |
- JSON document is empty. | |
- Invalid value. | |
- Missing name for object member. | |
- Missing colon after name of object member. | |
- Missing comma or right curly brace after object member. | |
- Missing comma or ] after array element. | |
- Invalid \uXXXX escape. | |
- Invalid surrogate pair. | |
- Invalid backslash escape. | |
- Missing closing quotation mark in string. | |
- Numeric overflow. | |
- Missing fraction in number. | |
- Missing exponent in number. | |
} | |
] | |
json-ctx: object [ | |
;----------------------------------------------------------- | |
;-- Generic support funcs | |
BOM: [ | |
UTF-8 #{EFBBBF} | |
UTF-16-BE #{FEFF} | |
UTF-16-LE #{FFFE} | |
UTF-32-BE #{0000FEFF} | |
UTF-32-LE #{FFFE0000} | |
] | |
BOM-UTF-16?: func [data [string! binary!]][ | |
any [find/match data BOM/UTF-16-BE find/match data BOM/UTF-16-LE] | |
] | |
BOM-UTF-32?: func [data [string! binary!]][ | |
any [find/match data BOM/UTF-32-BE find/match data BOM/UTF-32-LE] | |
] | |
; MOLD adds quotes string!, but not all any-string! values. | |
enquote: func [str [string!] "(modified)"][append insert str {"} {"}] | |
high-surrogate?: func [codepoint [integer!]][ | |
all [codepoint >= D800h codepoint <= DBFFh] | |
] | |
low-surrogate?: func [codepoint [integer!]][ | |
all [codepoint >= DC00h codepoint <= DFFFh] | |
] | |
; map-each: function [ | |
; "Evaluates body for each value in a series, returning all results." | |
; 'word [word! block!] "Word, or words, to set on each iteration" | |
; data [series!] ; map! | |
; body [block!] | |
; ][ | |
; collect [foreach :word data [keep/only do body]] | |
; ] | |
translit: func [ | |
"Tansliterate sub-strings in a string" | |
string [string!] "Input (modified)" | |
rule [block! bitset!] "What to change" | |
xlat [block! function!] "Translation table or function. MUST map a string! to a string!." | |
/local val | |
][ | |
parse string [ | |
some [ | |
change copy val rule (val either block? :xlat [xlat/:val][xlat val]) | |
| skip | |
] | |
] | |
string | |
] | |
;----------------------------------------------------------- | |
;-- JSON backslash escaping | |
;TBD: I think this can be improved. --Gregg | |
json-to-red-escape-table: [ | |
; JSON Red | |
{\"} "^"" | |
{\\} "\" | |
{\/} "/" | |
{\b} "^H" ; #"^(back)" | |
{\f} "^L" ; #"^(page)" | |
{\n} "^/" | |
{\r} "^M" | |
{\t} "^-" | |
] | |
red-to-json-escape-table: reverse copy json-to-red-escape-table | |
json-esc-ch: charset {"t\/nrbf} ; Backslash escaped JSON chars | |
json-escaped: [#"\" json-esc-ch] ; Backslash escape rule | |
red-esc-ch: charset {^"^-\/^/^M^H^L} ; Red chars requiring JSON backslash escapes | |
decode-backslash-escapes: func [string [string!] "(modified)"][ | |
translit string json-escaped json-to-red-escape-table | |
] | |
encode-backslash-escapes: func [string [string!] "(modified)"][ | |
translit string red-esc-ch red-to-json-escape-table | |
] | |
;ss: copy string: {abc\"\\\/\b\f\n\r\txyz} | |
;decode-backslash-escapes string | |
;encode-backslash-escapes string | |
;ss = string | |
;----------------------------------------------------------- | |
;-- JSON decoder | |
;----------------------------------------------------------- | |
;# Basic rules | |
ws: charset " ^-^/^M" ; Whitespace | |
ws*: [any ws] | |
ws+: [some ws] | |
sep: [ws* #"," ws*] ; JSON value separator | |
digit: charset "0123456789" | |
non-zero-digit: charset "123456789" | |
hex-char: charset "0123456789ABCDEFabcdef" | |
ctrl-char: charset [#"^@" - #"^_"] ; Control chars 0-31 | |
chars: charset [not {\"} #"^@" - #"^_"] ; Unescaped chars (NOT creates a virtual bitset) | |
; TBD: Unicode | |
;not-low-ascii-char: charset [not #"^(00)" - #"^(127)"] | |
;not-ascii-char: charset [not #"^(00)" - #"^(255)"] | |
; everything but \ and " | |
; Defining it literally this way, rather than a [NOT charset] rule, takes ~70K | |
; Need to see if it's faster one way or the other. | |
; unescaped-char: charset [ | |
; #"^(20)" - #"^(21)" ; " !" | |
; #"^(23)" - #"^(5B)" ; #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[ | |
; #"^(5D)" - #"^(10FFF)" ; ]^^_`abcdefghijklmnopqrstuvwxyz{|}~ ...U+ | |
; ] | |
;----------------------------------------------------------- | |
;-- JSON value rules | |
;----------------------------------------------------------- | |
;----------------------------------------------------------- | |
;-- Number | |
sign: [#"-"] | |
; Integers can't have leading zeros, but zero by itself is valid. | |
int: [[non-zero-digit any digit] | digit] | |
frac: [#"." some digit] | |
exp: [[#"e" | #"E"] opt [#"+" | #"-"] some digit] | |
number: [opt sign int opt frac opt exp] | |
numeric-literal: :number | |
;----------------------------------------------------------- | |
;-- String | |
string-literal: [ | |
#"^"" copy _str [ | |
any [some chars | #"\" [#"u" 4 hex-char | json-esc-ch]] | |
] #"^"" ( | |
if not empty? _str: any [_str copy ""] [ | |
;!! If we reverse the decode-backslash-escapes and replace-unicode-escapes | |
;!! calls, the string gets munged (extra U+ chars). Need to investigate. | |
decode-backslash-escapes _str ; _str is modified | |
replace-unicode-escapes _str ; _str is modified | |
;replace-unicode-escapes decode-backslash-escapes _str | |
] | |
) | |
] | |
decode-unicode-char: func [ | |
"Convert \uxxxx format (NOT simple JSON backslash escapes) to a Unicode char" | |
ch [string!] "4 hex digits" | |
][ | |
buf: {#"^^(0000)"} ; Don't COPY buffer, reuse it | |
if not parse ch [4 hex-char] [return none] ; Validate input data | |
attempt [load head change at buf 5 ch] ; Replace 0000 section in buf | |
] | |
replace-unicode-escapes: func [ | |
s [string!] "(modified)" | |
/local c | |
][ | |
parse s [ | |
any [ | |
some chars ; Pass over unescaped chars | |
| json-escaped ; Pass over simple backslash escapes | |
| change ["\u" copy c 4 hex-char] (decode-unicode-char c) | |
;| "\u" followed by anything else is an invalid \uXXXX escape | |
] | |
] | |
s | |
] | |
;str: {\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%&*()_+-=[]{}|;:',./<>?} | |
;mod-str: decode-backslash-escapes json-ctx/replace-unicode-escapes copy str | |
;mod-str: json-ctx/replace-unicode-escapes decode-backslash-escapes copy str | |
;----------------------------------------------------------- | |
;-- Object | |
json-object: [ | |
; Emit a new block to our output target, and push it on our | |
; working stack, to handle nested structures. Emit returns | |
; the insertion point for another value to go out into '_res, | |
; but we want the target to be the block we just added, so | |
; we reset '_res to that after 'emit is done. | |
#"{" (push emit copy [] _res: last _res) | |
ws* opt property-list | |
; This is a little confusing. We're at the tail of our current | |
; output target, which is on our stack. We pop that, then need | |
; to back up one, which puts us AT the block of values we | |
; collected for this object in our output target. i.e., the | |
; values are in a sub-block at the first position now. We use | |
; that (FIRST) to make a map! and replace the block of values | |
; with the map! we just made. Note that a map is treated as a | |
; single value, like an object. Using a block as the new value | |
; requires using `change/only`. | |
#"}" ( | |
_res: back pop | |
_res: change _res make map! first _res | |
) | |
] | |
property-list: [property any [sep property]] | |
property: [json-name (emit _str) json-value] | |
json-name: [ws* string-literal ws* #":"] | |
;----------------------------------------------------------- | |
;-- List | |
array-list: [json-value any [sep json-value]] | |
json-array: [ | |
; Emit a new block to our output target, and push it on our | |
; working stack, to handle nested structures. Emit returns | |
; the insertion point for another value to go out into '_res, | |
; but we want the target to be the block we just added, so | |
; we reset '_res to that after 'emit is done. | |
#"[" (push emit copy [] _res: last _res) | |
ws* opt array-list | |
#"]" (_res: pop) | |
] | |
;----------------------------------------------------------- | |
;-- Any JSON Value (top level JSON parse rule) | |
json-value: [ | |
ws* | |
[ | |
"true" (emit true) ; Literals must be lowercase | |
| "false" (emit false) | |
| "null" (emit none) | |
| json-object | |
| json-array | |
| string-literal (emit _str) | |
| copy _str numeric-literal (emit load _str) ; Number | |
mark: ; Set mark for failure location | |
] | |
ws* | |
] | |
;----------------------------------------------------------- | |
;-- Decoder data structures | |
; The stack is used to handle nested structures (objects and lists) | |
stack: copy [] | |
push: func [val][append/only stack val] | |
pop: does [take/last stack] | |
_out: none ; Our overall output target/result | |
_res: none ; The current output position where new values are inserted | |
_str: none ; Where string value parse results go | |
mark: none ; Current parse position | |
; Add a new value to our output target, and set the position for | |
; the next emit to the tail of the insertion. | |
;!! I really don't like how this updates _res as a side effect. --Gregg | |
emit: func [value][_res: insert/only _res value] | |
;----------------------------------------------------------- | |
;-- Main decoder func | |
set 'load-json func [ | |
[catch] | |
"Convert a json string to Red data" | |
input [string!] "The json string" | |
][ | |
_out: _res: copy [] ; These point to the same position to start with | |
mark: input | |
either parse input json-value [pick _out 1][ | |
throw make error! form reduce [ | |
"Invalid json string. Near:" | |
either tail? mark ["<end of input>"] [mold copy/part mark 40] | |
] | |
] | |
] | |
;------------------------------------------------------------------------------- | |
;------------------------------------------------------------------------------- | |
;------------------------------------------------------------------------------- | |
;----------------------------------------------------------- | |
;-- JSON encoder | |
;----------------------------------------------------------- | |
; Indentation support, so we can make the JSON output look decent. | |
dent: copy "" | |
dent-size: 4 | |
indent: does [append/dup dent #" " dent-size] | |
outdent: does [remove/part dent dent-size] | |
encode-char: func [ | |
"Convert a single char to \uxxxx format (NOT simple JSON backslash escapes)." | |
char [char! string!] | |
][ | |
if string? char [char: first char] | |
;rejoin ["\u" to-hex/size to integer! char 4] | |
append copy "\u" to-hex/size to integer! char 4 | |
] | |
;------------------------------------------------------------------------------- | |
;!! This is an optimization. The main reason it's here is that Red doesn't | |
;!! have a GC yet. Generating the lookup table once, and using that, prevents | |
;!! repeated block allocations every time we encode a control character. | |
make-ctrl-char-esc-table: function [][ | |
collect [ | |
;!! FORM is used here, when building the table, because TRANSLIT | |
; requires values to be strings. Yes, that's leaking it's | |
; abstraction a bit, which has to do with it using COPY vs SET | |
; in its internal PARSE rule. | |
keep reduce [form ch: make char! 0 encode-char ch] | |
repeat i 31 [keep reduce [form ch: make char! i encode-char ch]] | |
] | |
] | |
ctrl-char-esc-table: make-ctrl-char-esc-table | |
;------------------------------------------------------------------------------- | |
encode-control-chars: func [ | |
"Convert all control chars in string to \uxxxx format" | |
string [any-string!] "(modified)" | |
][ | |
if find string ctrl-char [ | |
;translit string ctrl-char :encode-char ; Use function to encode | |
translit string ctrl-char ctrl-char-esc-table ; Optimized table lookup approach | |
] | |
string | |
] | |
;encode-control-chars "^@^A^B^C^D^E^F^G^H^-^/^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^(1E)^_ " | |
; The reason this func does not copy the string is that a lot of | |
; values will have been FORMed or MOLDed when they are passed to | |
; it, so there's no sense in copying them again. The only time it's | |
; a problem is for string values themselves. | |
;TBD: Encode unicode chars? | |
encode-red-string: func [string "(modified) Caller should copy"][ | |
encode-control-chars encode-backslash-escapes string | |
;TBD translit string not-ascii-char :encode-char | |
] | |
red-to-json-name: func [val][ | |
append enquote encode-red-string form val ":" | |
] | |
; Types that map directly to a known JSON type. | |
json-type!: union any-block! union any-string! make typeset! [ | |
none! logic! integer! float! percent! map! object! ; decimal! | |
] | |
red-to-json-value: func [val][ | |
;?? Is it worth the extra lines to make each type a separate case? | |
; The switch cases will look nicer if we do; more table like. | |
switch/default type?/word :val [ | |
string! [enquote encode-red-string copy val] ; COPY to prevent mutation | |
none! ["null"] ; JSON value MUST be lowercase | |
logic! [pick ["true" "false"] val] ; JSON value MUST be lowercase | |
integer! float! [form val] ; TBD: add decimal! | |
percent! [form make float! val] ; FORM percent! includes sigil | |
map! object! [map-to-json-object val] ; ?? hash! | |
word! [ | |
either all [ | |
not error? try [get val] ; Error means word ref's no value. FORM and escape it. | |
find json-type! type? get val ; Not a type json understands. FORM and escape it. | |
][ | |
red-to-json-value get val | |
][ | |
; No-value error, or non-JSON types become quoted strings. | |
enquote encode-red-string form val | |
] | |
] | |
][ | |
either any-block? :val [block-to-json-list val] [ | |
; FORM forces binary! values to strings, so newlines escape properly. | |
enquote encode-red-string either any-string? :val [form val] [mold :val] | |
] | |
] | |
] | |
;TBD: Eventually we should have a nice dlm string tool in Red. Is it worth | |
; including our own for the list/object cases? | |
block-to-json-list: func [block [any-block!] /local result sep][ | |
indent | |
result: copy "[^/" | |
foreach value block [ | |
append result rejoin [dent red-to-json-value :value ",^/"] | |
] | |
outdent | |
append clear any [find/last result "," tail result] rejoin ["^/" dent "]"] | |
;single-line-reformat result | |
result | |
] | |
map-to-json-object: func [map [map!] /local result sep][ | |
indent | |
result: copy "{^/" | |
foreach word words-of map [ | |
append result rejoin [ | |
dent red-to-json-name :word " " | |
red-to-json-value map/:word ",^/" | |
] | |
] | |
outdent | |
append clear any [find/last result "," tail result] rejoin ["^/" dent "}"] | |
;single-line-reformat result | |
result | |
] | |
;----------------------------------------------------------- | |
;-- Main encoder func | |
set 'to-json function [ | |
[catch] | |
"Convert red data to a json string" | |
data | |
][ | |
result: make string! 4000 ;!! factor this up from molded data length? | |
foreach value compose/only [(data)] [ | |
append result red-to-json-value value | |
] | |
result | |
] | |
; Even if we don't do full pretty formatting of JSON, it might still be nice | |
; to do the single-line bit. | |
; single-line-cleanup: function [string][ | |
; table: ["{ " "{" "[ " "[" " }" "}" " ]" "]"] ; From/To Old/New Dirty/Clean values | |
; dirty: ["{ " | "[ " | " }" | " ]"] | |
; translit string dirty table | |
; ] | |
; ;print mold single-line-cleanup "{ a [ b { c } d ] f }" | |
; | |
; single-line-reformat: function [ | |
; "Reformats a block/object to a single line if it's short enough." | |
; val | |
; ][ | |
; either 80 >= length? join dent s: trim/lines copy val [ | |
; single-line-cleanup s | |
; ][val] | |
; ] | |
] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment