1
0
Fork 0
agulator/Parse.agda

140 lines
4.9 KiB
Plaintext
Raw Normal View History

2022-09-28 05:05:16 +00:00
module Parse where
2022-09-29 01:57:05 +00:00
open import Agda.Builtin.Bool
2022-09-28 05:05:16 +00:00
open import Agda.Builtin.Char
open import Agda.Builtin.List
open import Agda.Builtin.Maybe
open import Agda.Builtin.Nat
open import Agda.Builtin.String
open import Data.List using (_++_; reverse)
2022-09-28 05:05:16 +00:00
open import Util
data Token : Set where
Digit : Nat → Token
Delim : Char → Token
Oper : Char → Token
Skip : Char → Token
Term : Token
2022-09-28 22:06:38 +00:00
record Result (A : Set) : Set where
constructor emit
field
2022-09-29 13:55:03 +00:00
val : Maybe A
2022-09-28 22:06:38 +00:00
rem : List Char
2022-09-29 13:30:16 +00:00
-- emit a result with a value and continue parsing
2022-09-29 02:31:34 +00:00
emit↓ : {A : Set} → A → List Char → Result A
emit↓ a rem = emit (just a) rem
2022-09-29 13:30:16 +00:00
-- emit a result without a value and backtrack
2022-09-29 02:31:34 +00:00
emit↑ : {A : Set} → List Char → Result A
emit↑ rem = emit nothing rem
2022-09-29 13:30:16 +00:00
-- result to string
2022-09-28 22:06:38 +00:00
showResult : {A : Set} → (A → String) → Result A → String
showResult f (emit nothing rem) = primStringAppend "remainder: " (primStringFromList rem)
2022-09-29 02:31:34 +00:00
showResult f (emit (just r) []) = primStringAppend "result: " (f r)
showResult f (emit (just r) xs) = primStringAppend (primStringAppend "result: " (f r)) (primStringAppend ", remainder: " (primStringFromList xs))
2022-09-28 22:06:38 +00:00
-- take consecutive occurences of a character set
takeCons : List Char → List Char → Result (List Char)
2022-09-29 02:31:34 +00:00
takeCons _ [] = emit↑ []
takeCons [] r = emit↑ r
2022-09-28 22:06:38 +00:00
takeCons cs (x ∷ xs) with (findCharIndex 0 x cs)
2022-09-29 02:31:34 +00:00
... | nothing = emit↑ (x ∷ xs)
2022-09-28 22:06:38 +00:00
... | just n with (takeCons cs xs)
2022-09-29 02:31:34 +00:00
... | emit nothing rem = emit↓ (x ∷ []) xs
2022-09-29 13:55:03 +00:00
... | emit (just val) rem = emit↓ (x ∷ val) rem
-- ignore consecutive characters
ignoreCons : List Char → List Char → List Char
ignoreCons _ [] = []
ignoreCons [] r = r
ignoreCons cs xs with takeCons cs xs
... | emit nothing rem = rem
... | emit (just val) rem = rem
2022-09-28 04:12:48 +00:00
digits : List Char
digits = primStringToList "0123456789"
2022-09-28 22:34:13 +00:00
opers : List Char
2022-09-29 01:57:05 +00:00
opers = primStringToList "-+*/"
2022-09-28 22:34:13 +00:00
2022-09-29 13:55:03 +00:00
skips : List Char
skips = primStringToList " "
-- parse a single character into a typed token
2022-09-28 04:12:48 +00:00
parseChar : Char → Token
parseChar '0' = Digit 0
parseChar '1' = Digit 1
parseChar '2' = Digit 2
parseChar '3' = Digit 3
parseChar '4' = Digit 4
parseChar '5' = Digit 5
parseChar '6' = Digit 6
parseChar '7' = Digit 7
parseChar '8' = Digit 8
parseChar '9' = Digit 9
parseChar ',' = Delim ','
2022-09-28 23:16:26 +00:00
parseChar '-' = Oper '-'
2022-09-28 04:12:48 +00:00
parseChar '+' = Oper '+'
2022-09-29 01:57:05 +00:00
parseChar '*' = Oper '*'
parseChar '/' = Oper '/'
2022-09-28 22:06:38 +00:00
parseChar ' ' = Skip ' '
2022-09-28 04:12:48 +00:00
parseChar _ = Term
-- parse a number from a list of characters
2022-09-28 22:06:38 +00:00
parseNat : Maybe Nat → List Char → Result Nat
parseNat a [] = emit a []
2022-09-28 05:05:16 +00:00
parseNat a (x ∷ xs) with parseChar x
2022-09-30 00:43:35 +00:00
... | Digit n = parseNat (just (((default 0 a) * 10) + n)) xs
... | _ = emit↑ xs
2022-09-28 05:05:16 +00:00
2022-09-28 22:06:38 +00:00
takeNat : List Char → Result Nat
2022-09-30 00:43:35 +00:00
takeNat s with takeCons digits s
... | emit nothing rem₁ = emit↑ rem₁
... | emit (just xs) rem₁ with parseNat nothing xs
... | emit (just n) rem₂ = emit↓ n rem₁
... | emit _ rem₂ = emit↑ rem₁
2022-09-28 22:06:38 +00:00
-- provided for completeness with the parse/take pair above, but this one is not used
parseOper : List Char → Result Token
parseOper [] = emit↑ []
parseOper (x ∷ xs) with parseChar x
... | Oper o = emit↓ (Oper o) xs
... | _ = emit↑ xs
2022-09-28 22:06:38 +00:00
takeOper : List Char → Result Token
2022-09-30 00:43:35 +00:00
takeOper s with takeCons opers s
2022-09-29 02:31:34 +00:00
... | emit nothing rem = emit↑ rem
... | emit (just []) rem = emit↑ rem
2022-09-28 22:06:38 +00:00
... | emit (just (x ∷ xs)) rem with parseChar x
2022-09-29 02:31:34 +00:00
... | Oper o = emit↓ (Oper o) (xs ++ rem)
... | _ = emit↑ s
2022-09-30 01:16:32 +00:00
-- why doesn't this version work?
2022-09-30 00:43:35 +00:00
-- ... | emit (just xs) rem with parseOper xs
2022-09-30 01:16:32 +00:00
-- ... | emit (just (Oper o)) rem₂ = emit↓ (Oper o) rem₂
-- ... | emit _ rem₂ = emit↑ rem
2022-09-30 00:43:35 +00:00
2022-09-29 13:30:16 +00:00
-- this should maybe be its own module or something
2022-09-30 00:43:35 +00:00
record BinExpr : Set where
constructor bin
field
oper : Token
lhs : Token
rhs : Token
2022-09-28 05:05:16 +00:00
2022-09-28 22:06:38 +00:00
takeBin : List Char → Result BinExpr
2022-09-30 00:43:35 +00:00
takeBin s with takeNat (ignoreCons skips s)
... | emit nothing rem₁ = emit↑ s
... | emit (just res₁) rem₁ with takeOper (ignoreCons skips rem₁)
... | emit nothing rem₂ = emit↑ rem₁
... | emit (just oper) rem₂ with takeNat (ignoreCons skips rem₂)
... | emit nothing rem₃ = emit↑ rem₁
... | emit (just res₃) rem₃ = emit↓ (bin oper (Digit res₁) (Digit res₃)) rem₃
2022-09-28 04:12:48 +00:00
2022-09-28 22:06:38 +00:00
takeLine : List Char → List (Result BinExpr)
takeLine s = map takeBin (map reverse (reverse (split (';' ∷ []) s)))