| | 418 | |
| | 419 | |
| | 420 | ----------------------------------------------------------- |
| | 421 | -- Chars & Strings |
| | 422 | ----------------------------------------------------------- |
| | 423 | ----------------------------------------------------------- |
| | 424 | -- Numbers |
| | 425 | ----------------------------------------------------------- |
| | 426 | -- naturalOrFloat :: CharParser st (Either Integer Double) |
| | 427 | naturalOrFloat = lexeme (natFloat) <?> "number" |
| | 428 | |
| | 429 | float = lexeme floating <?> "float" |
| | 430 | integer = lexeme int <?> "integer" |
| | 431 | natural = lexeme nat <?> "natural" |
| | 432 | |
| | 433 | |
| | 434 | -- floats |
| | 435 | floating = do{ n <- decimal |
| | 436 | ; fractExponent n |
| | 437 | } |
| | 438 | |
| | 439 | |
| | 440 | natFloat = do{ char '0' |
| | 441 | ; zeroNumFloat |
| | 442 | } |
| | 443 | <|> decimalFloat |
| | 444 | |
| | 445 | zeroNumFloat = do{ n <- hexadecimal <|> octal |
| | 446 | ; return (Left n) |
| | 447 | } |
| | 448 | <|> decimalFloat |
| | 449 | <|> fractFloat 0 |
| | 450 | <|> return (Left 0) |
| | 451 | |
| | 452 | decimalFloat = do{ n <- decimal |
| | 453 | ; option (Left n) |
| | 454 | (fractFloat n) |
| | 455 | } |
| | 456 | |
| | 457 | fractFloat n = do{ f <- fractExponent n |
| | 458 | ; return (Right f) |
| | 459 | } |
| | 460 | |
| | 461 | fractExponent n = do{ fract <- fraction |
| | 462 | ; expo <- option 1.0 exponent' |
| | 463 | ; return ((fromInteger n + fract)*expo) |
| | 464 | } |
| | 465 | <|> |
| | 466 | do{ expo <- exponent' |
| | 467 | ; return ((fromInteger n)*expo) |
| | 468 | } |
| | 469 | |
| | 470 | fraction = do{ char '.' |
| | 471 | ; digits <- many1 digit <?> "fraction" |
| | 472 | ; return (foldr op 0.0 digits) |
| | 473 | } |
| | 474 | <?> "fraction" |
| | 475 | where |
| | 476 | op d f = (f + fromIntegral (digitToInt d))/10.0 |
| | 477 | |
| | 478 | exponent' = do{ oneOf "eE" |
| | 479 | ; f <- sign |
| | 480 | ; e <- decimal <?> "exponent" |
| | 481 | ; return (power (f e)) |
| | 482 | } |
| | 483 | <?> "exponent" |
| | 484 | where |
| | 485 | power e | e < 0 = 1.0/power(-e) |
| | 486 | | otherwise = fromInteger (10^e) |
| | 487 | |
| | 488 | |
| | 489 | -- integers and naturals |
| | 490 | int = do{ f <- lexeme sign |
| | 491 | ; n <- nat |
| | 492 | ; return (f n) |
| | 493 | } |
| | 494 | |
| | 495 | -- sign :: CharParser st (Integer -> Integer) |
| | 496 | sign = (char '-' >> return negate) |
| | 497 | <|> (char '+' >> return id) |
| | 498 | <|> return id |
| | 499 | |
| | 500 | nat = zeroNumber <|> decimal |
| | 501 | |
| | 502 | zeroNumber = do{ char '0' |
| | 503 | ; hexadecimal <|> octal <|> decimal <|> return 0 |
| | 504 | } |
| | 505 | <?> "" |
| | 506 | |
| | 507 | decimal = number 10 digit |
| | 508 | hexadecimal = do{ oneOf "xX"; number 16 hexDigit } |
| | 509 | octal = do{ oneOf "oO"; number 8 octDigit } |
| | 510 | |
| | 511 | ----------------------------------------------------------- |
| | 512 | -- Identifiers & Reserved words |
| | 513 | ----------------------------------------------------------- |
| | 514 | identifier = lexeme $ try $ ident |
| | 515 | |
| | 516 | ident |
| | 517 | = do{ c <- identStart |
| | 518 | ; cs <- many identLetter |
| | 519 | ; return (c:cs) |
| | 520 | } |
| | 521 | <?> "identifier" |
| | 522 | |
| | 523 | ----------------------------------------------------------- |
| | 524 | -- White space & symbols |
| | 525 | ----------------------------------------------------------- |
| | 526 | lexeme p |
| | 527 | = do{ x <- p; whiteSpace; return x } |
| | 528 | |
| | 529 | |
| | 530 | --whiteSpace |
| | 531 | whiteSpace = skipMany (simpleSpace <|> comment) |
| | 532 | |
| | 533 | comment = do |
| | 534 | char '#' <?> "comment" |
| | 535 | pos <- getPosition |
| | 536 | if sourceColumn pos /= 2 then multiLineComment <|> skipToLineEnd else do |
| | 537 | -- Beginning of line - parse #line directive |
| | 538 | isPlain <- (<|> return True) $ try $ do |
| | 539 | string "line" |
| | 540 | many1 $ satisfy (\x -> isSpace x && x /= '\n') |
| | 541 | return False |
| | 542 | if isPlain then skipToLineEnd else do |
| | 543 | line <- decimal |
| | 544 | file <- (<|> return Nothing) $ try $ do |
| | 545 | many1 $ satisfy (\x -> isSpace x && x /= '\n') |
| | 546 | fileNameQuoted <|> fileNameBare |
| | 547 | if file == Just Nothing then skipToLineEnd else do |
| | 548 | many $ satisfy (/= '\n') |
| | 549 | setPosition $ pos |
| | 550 | `setSourceLine` (fromInteger line - 1) |
| | 551 | `setSourceColumn` 1 |
| | 552 | `setSourceName` maybe (sourceName pos) fromJust file |
| | 553 | return () |
| | 554 | |
| | 555 | fileNameQuoted = try $ do |
| | 556 | char '"' |
| | 557 | file <- many (satisfy (/= '"')) |
| | 558 | char '"' |
| | 559 | many $ satisfy (\x -> isSpace x && x /= '\n') |
| | 560 | lookAhead (satisfy (== '\n')) |
| | 561 | return $ Just $ Just file |
| | 562 | |
| | 563 | fileNameBare = try $ do |
| | 564 | file <- many1 $ satisfy (not . isSpace) |
| | 565 | many $ satisfy (\x -> isSpace x && x /= '\n') |
| | 566 | (<|> return (Just Nothing)) $ try $ do |
| | 567 | lookAhead (satisfy (== '\n')) |
| | 568 | return $ Just $ Just file |
| | 569 | |
| | 570 | skipToLineEnd = do |
| | 571 | skipMany (satisfy (/= '\n')) |
| | 572 | return () |
| | 573 | |
| | 574 | simpleSpace = |
| | 575 | skipMany1 (satisfy isSpace) |
| | 576 | |
| | 577 | -- XXX - nesting |
| | 578 | multiLineComment = do |
| | 579 | openOne <- satisfy (\x -> balancedDelim x /= x) |
| | 580 | more <- many (char openOne) |
| | 581 | let closeOne = balancedDelim openOne |
| | 582 | openAll = string (openOne:more) |
| | 583 | closeAll = string (replicate (1 + length more) (balancedDelim openOne)) |
| | 584 | scanOne = do |
| | 585 | c <- anyChar |
| | 586 | if c == closeOne then return () else do |
| | 587 | if c == openOne then scanOne >> scanOne else do |
| | 588 | scanOne |
| | 589 | scanAll = choice |
| | 590 | [ do { try closeAll; return () } |
| | 591 | , do { try openAll; scanAll; scanAll } |
| | 592 | , do { anyChar; scanAll } |
| | 593 | ] |
| | 594 | if null more then scanOne else scanAll |