diff options
Diffstat (limited to 'stdlib/source/library/lux/control/parser/binary.lux')
-rw-r--r-- | stdlib/source/library/lux/control/parser/binary.lux | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/stdlib/source/library/lux/control/parser/binary.lux b/stdlib/source/library/lux/control/parser/binary.lux new file mode 100644 index 000000000..af28caeae --- /dev/null +++ b/stdlib/source/library/lux/control/parser/binary.lux @@ -0,0 +1,275 @@ +(.module: + [library + [lux (#- and or nat int rev list type) + [type (#+ :share)] + [abstract + [hash (#+ Hash)] + [monad (#+ do)]] + [control + ["." try (#+ Try)] + ["." exception (#+ exception:)]] + [data + ["/" binary (#+ Binary)] + [text + ["%" format (#+ format)] + [encoding + ["." utf8]]] + [collection + ["." list] + ["." row (#+ Row)] + ["." set (#+ Set)]]] + [macro + ["." template]] + [math + [number + ["n" nat] + ["." frac]]]]] + ["." // ("#\." monad)]) + +(type: #export Offset Nat) + +(type: #export Parser + (//.Parser [Offset Binary])) + +(exception: #export (binary_was_not_fully_read {binary_length Nat} {bytes_read Nat}) + (exception.report + ["Binary length" (%.nat binary_length)] + ["Bytes read" (%.nat bytes_read)])) + +(def: #export (run parser input) + (All [a] (-> (Parser a) Binary (Try a))) + (case (parser [0 input]) + (#try.Failure msg) + (#try.Failure msg) + + (#try.Success [[end _] output]) + (let [length (/.size input)] + (if (n.= end length) + (#try.Success output) + (exception.throw ..binary_was_not_fully_read [length end]))))) + +(def: #export end? + (Parser Bit) + (function (_ (^@ input [offset data])) + (#try.Success [input (n.= offset (/.size data))]))) + +(def: #export offset + (Parser Offset) + (function (_ (^@ input [offset data])) + (#try.Success [input offset]))) + +(def: #export remaining + (Parser Nat) + (function (_ (^@ input [offset data])) + (#try.Success [input (n.- offset (/.size data))]))) + +(type: #export Size Nat) + +(def: #export size/8 Size 1) +(def: #export size/16 Size (n.* 2 size/8)) +(def: #export size/32 Size (n.* 2 size/16)) +(def: #export size/64 Size (n.* 2 size/32)) + +(template [<name> <size> <read>] + [(def: #export <name> + (Parser I64) + (function (_ [offset binary]) + (case (<read> offset binary) + (#try.Success data) + (#try.Success [(n.+ <size> offset) binary] data) + + (#try.Failure error) + (#try.Failure error))))] + + [bits/8 ..size/8 /.read/8] + [bits/16 ..size/16 /.read/16] + [bits/32 ..size/32 /.read/32] + [bits/64 ..size/64 /.read/64] + ) + +(template [<name> <type>] + [(def: #export <name> (Parser <type>) ..bits/64)] + + [nat Nat] + [int Int] + [rev Rev] + ) + +(def: #export frac + (Parser Frac) + (//\map frac.from_bits ..bits/64)) + +(exception: #export (invalid_tag {range Nat} {byte Nat}) + (exception.report + ["Tag range" (%.nat range)] + ["Tag value" (%.nat byte)])) + +(template: (!variant <case>+) + (do {! //.monad} + [flag (: (Parser Nat) + ..bits/8)] + (`` (case flag + (^template [<number> <tag> <parser>] + [<number> (\ ! map (|>> <tag>) <parser>)]) + ((~~ (template.splice <case>+))) + _ (//.lift (exception.throw ..invalid_tag [(~~ (template.count <case>+)) flag])))))) + +(def: #export (or left right) + (All [l r] (-> (Parser l) (Parser r) (Parser (| l r)))) + (!variant [[0 #.Left left] + [1 #.Right right]])) + +(def: #export (rec body) + (All [a] (-> (-> (Parser a) (Parser a)) (Parser a))) + (function (_ input) + (let [parser (body (rec body))] + (parser input)))) + +(def: #export any + (Parser Any) + (//\wrap [])) + +(exception: #export (not_a_bit {value Nat}) + (exception.report + ["Expected values" "either 0 or 1"] + ["Actual value" (%.nat value)])) + +(def: #export bit + (Parser Bit) + (do //.monad + [value (: (Parser Nat) + ..bits/8)] + (case value + 0 (wrap #0) + 1 (wrap #1) + _ (//.lift (exception.throw ..not_a_bit [value]))))) + +(def: #export (segment size) + (-> Nat (Parser Binary)) + (function (_ [offset binary]) + (case size + 0 (#try.Success [[offset binary] (/.create 0)]) + _ (|> binary + (/.slice offset size) + (\ try.monad map (|>> [[(n.+ size offset) binary]])))))) + +(template [<name> <bits>] + [(def: #export <name> + (Parser Binary) + (do //.monad + [size (//\map .nat <bits>)] + (..segment size)))] + + [binary/8 ..bits/8] + [binary/16 ..bits/16] + [binary/32 ..bits/32] + [binary/64 ..bits/64] + ) + +(template [<name> <binary>] + [(def: #export <name> + (Parser Text) + (do //.monad + [utf8 <binary>] + (//.lift (\ utf8.codec decode utf8))))] + + [utf8/8 ..binary/8] + [utf8/16 ..binary/16] + [utf8/32 ..binary/32] + [utf8/64 ..binary/64] + ) + +(def: #export text ..utf8/64) + +(template [<name> <bits>] + [(def: #export (<name> valueP) + (All [v] (-> (Parser v) (Parser (Row v)))) + (do //.monad + [count (: (Parser Nat) + <bits>)] + (loop [index 0 + output (:share [v] + (Parser v) + valueP + + (Row v) + row.empty)] + (if (n.< count index) + (do //.monad + [value valueP] + (recur (.inc index) + (row.add value output))) + (//\wrap output)))))] + + [row/8 ..bits/8] + [row/16 ..bits/16] + [row/32 ..bits/32] + [row/64 ..bits/64] + ) + +(def: #export maybe + (All [a] (-> (Parser a) (Parser (Maybe a)))) + (..or ..any)) + +(def: #export (list value) + (All [a] (-> (Parser a) (Parser (List a)))) + (..rec + (|>> (//.and value) + (..or ..any)))) + +(exception: #export set_elements_are_not_unique) + +(def: #export (set hash value) + (All [a] (-> (Hash a) (Parser a) (Parser (Set a)))) + (do //.monad + [raw (..list value) + #let [output (set.from_list hash raw)] + _ (//.assert (exception.construct ..set_elements_are_not_unique []) + (n.= (list.size raw) + (set.size output)))] + (wrap output))) + +(def: #export name + (Parser Name) + (//.and ..text ..text)) + +(def: #export type + (Parser Type) + (..rec + (function (_ type) + (let [pair (//.and type type) + indexed ..nat + quantified (//.and (..list type) type)] + (!variant [[0 #.Primitive (//.and ..text (..list type))] + [1 #.Sum pair] + [2 #.Product pair] + [3 #.Function pair] + [4 #.Parameter indexed] + [5 #.Var indexed] + [6 #.Ex indexed] + [7 #.UnivQ quantified] + [8 #.ExQ quantified] + [9 #.Apply pair] + [10 #.Named (//.and ..name type)]]))))) + +(def: #export location + (Parser Location) + ($_ //.and ..text ..nat ..nat)) + +(def: #export code + (Parser Code) + (..rec + (function (_ recur) + (let [sequence (..list recur)] + (//.and ..location + (!variant [[0 #.Bit ..bit] + [1 #.Nat ..nat] + [2 #.Int ..int] + [3 #.Rev ..rev] + [4 #.Frac ..frac] + [5 #.Text ..text] + [6 #.Identifier ..name] + [7 #.Tag ..name] + [8 #.Form sequence] + [9 #.Tuple sequence] + [10 #.Record (..list (//.and recur recur))]])))))) |