1 module Parse(parse_circuit, parse_exact, parse_approx, parse_integer) where
    2 
    3 import Char
    4 import List
    5 import Maybe
    6 import Ratio
    7 
    8 import Types
    9 import ParseLib
   10 
   11 parse_circuit = parse (remove_right circuit whitespace)
   12 parse_exact   = parse (remove_right exact   whitespace)
   13 parse_approx  = parse (remove_right approx  whitespace)
   14 parse_integer = parse (remove_right integer whitespace)
   15 
   16 circuit :: Parser (Circuit, [Name])
   17 circuit = transform make_indices (repetition1 element)
   18   where
   19         make_indices list      = (circuit, names)
   20           where
   21                 list_with_types       = [(e, ("i:" ++ n1, "v:" ++ n2, "v:" ++ n3)) | (e, (n1, n2, n3)) <- list]
   22                 names         = (nub . ("v:ground" :) . concat) [[n1, n2, n3] | (_, (n1, n2, n3)) <- list_with_types]
   23                 circuit             = [(index n1, index n2, index n3, e) | (e, (n1, n2, n3)) <- list_with_types]
   24                 index name    = fromJust (lookup name (zip names [0..]))
   25 
   26 element :: Parser (Element, (Name, Name, Name))
   27 element = choice [conductor, resistor, capacitor, inductor, vsource, isource, junction]
   28   where
   29         conductor           = code 'g' (transform Conductor exact)
   30         resistor             = code 'r' (transform Resistor  exact)
   31         capacitor           = code 'c' (transform Capacitor (sequence2 exact exact))
   32         inductor             = code 'l' (transform Inductor  (sequence2 exact exact))
   33         vsource                     = code 'v' (transform Vsource   list)
   34         isource                     = code 'i' (transform Isource   list)
   35         junction             = code 'j' (transform Junction  (sequence3 exact exact exact))
   36 
   37         code c                = transform (\(n, e) -> (e, n)) . (sequence2 (remove_left (character c) (sequence3 name name name)))
   38         
   39 list    :: Parser List
   40 list    = repetition1 (enclose (character '(') (glue approx (character ',') approx) (character ')'))
   41 
   42 approx  :: Parser Approx
   43 approx  = transform circa exact
   44 
   45 exact   :: Parser Exact
   46 exact   = transform (\((sign, int), (frac, fact)) -> sign * (int + frac) * fact) (sequence2 (sequence2 sign integer) (sequence2 fraction factor))
   47   where
   48         sign                = transform make_sign (option (character '-'))
   49         make_sign ""     =  1 % 1
   50         make_sign "-"   = -1 % 1
   51         
   52         integer                     = transform make_integer (parse_while isDigit)
   53         make_integer s         = read s % 1
   54         
   55         fraction             = transform make_fraction (option (remove_left (character' '.') (parse_while isDigit)))
   56         make_fraction [ ]      = 0 % 1
   57         make_fraction [s]      = read s % read ('1' : map (const '0') s)
   58 
   59         factor                = transform make_factor (option (parse_if' (`elem` "afpnumkMGTPE")))
   60         make_factor "a"               = 1 % 1000000000000000000
   61         make_factor "f"               = 1 % 1000000000000000
   62         make_factor "p"               = 1 % 1000000000000
   63         make_factor "n"               = 1 % 1000000000
   64         make_factor "u"               = 1 % 1000000
   65         make_factor "m"               = 1 % 1000
   66         make_factor ""         = 1 % 1
   67         make_factor "k"               = 1000 % 1
   68         make_factor "M"               = 1000000 % 1
   69         make_factor "G"               = 1000000000 % 1
   70         make_factor "T"               = 1000000000000 % 1
   71         make_factor "P"               = 1000000000000000 % 1
   72         make_factor "E"               = 1000000000000000000 % 1
   73 
   74 integer :: Parser Integer
   75 integer = transform read (choice [cons (character '-') (parse_while isDigit), parse_while isDigit])
   76 
   77 name    :: Parser Name
   78 name    = parse_while isAlphaNum