reset a3, kut Charlie ;)
[tt2015.git] / a3 / code / Generics / GenParse.icl
diff --git a/a3/code/Generics/GenParse.icl b/a3/code/Generics/GenParse.icl
new file mode 100644 (file)
index 0000000..be4ccd7
--- /dev/null
@@ -0,0 +1,789 @@
+implementation module GenParse\r
+\r
+import StdGeneric, StdEnv, StdMaybe\r
+\r
+//---------------------------------------------------------------------------\r
+\r
+\r
+:: StringInput = { si_str :: !String, si_pos :: !Int} \r
+\r
+mkStringInput :: String -> StringInput \r
+mkStringInput str = {si_str = str, si_pos = 0}\r
+\r
+instance ParseInput StringInput where\r
+       parseInput s=:{si_pos, si_str}\r
+               #! size_str = size si_str\r
+               | size_str == si_pos \r
+                       = (Nothing, {s & si_str = si_str})\r
+               | otherwise\r
+                       #! ch = si_str.[si_pos]\r
+                       = (Just ch, {s & si_str = si_str, si_pos = inc si_pos})\r
+\r
+instance ParseInput File where \r
+       parseInput file \r
+               # (ok, c, file) = sfreadc file\r
+               | ok\r
+                       = (Just c, file)\r
+                       = (Nothing, file)\r
+                                               \r
+//---------------------------------------------------------------------------\r
+\r
+// lex tokens\r
+:: Token \r
+       = TokenInt Int\r
+       | TokenChar Char\r
+       | TokenReal Real \r
+       | TokenBool Bool\r
+       | TokenString String\r
+       | TokenIdent String\r
+       | TokenOpenPar\r
+       | TokenClosePar\r
+       | TokenOpenCurly\r
+       | TokenCloseCurly\r
+       | TokenOpenList\r
+       | TokenCloseList\r
+       | TokenComma\r
+       | TokenEnd\r
+       | TokenError String\r
+\r
+instance toString Token where\r
+       toString (TokenInt x) = toString x\r
+       toString (TokenChar x) = toString x\r
+       toString (TokenReal x) = toString x\r
+       toString (TokenBool x) = toString x\r
+       toString (TokenString x) = x\r
+       toString (TokenIdent x) = x\r
+       toString TokenOpenPar = "("\r
+       toString TokenClosePar = ")"\r
+       toString TokenOpenCurly = "{"\r
+       toString TokenCloseCurly = "}"\r
+       toString TokenOpenList = "["\r
+       toString TokenCloseList = "]"   \r
+       toString TokenComma = ","\r
+       toString TokenEnd = "<end>"\r
+       toString (TokenError err) = "<error: " +++ err +++ ">"\r
+\r
+// preparsed expressions\r
+:: Expr \r
+       = ExprInt Int\r
+       | ExprChar Char\r
+       | ExprReal Real \r
+       | ExprBool Bool\r
+       | ExprString String\r
+       | ExprIdent String\r
+       | ExprApp {Expr} \r
+       | ExprTuple {Expr}\r
+       | ExprField String Expr\r
+       | ExprRecord (Maybe String) {Expr}\r
+       | ExprList [Expr]\r
+       | ExprArray [Expr]\r
+       | ExprEnd Token\r
+       | ExprError String\r
+\r
+       // aux\r
+       | ExprUnit\r
+       | ExprAppInInfix {Expr} GenConsAssoc Int GenConsAssoc\r
+       | ExprPair Expr Expr\r
+\r
+\r
+instance toString Expr where\r
+       toString (ExprInt x) = toString x\r
+       toString (ExprChar x) = toString x\r
+       toString (ExprBool x) = toString x\r
+       toString (ExprReal x) = toString x\r
+       toString (ExprString x) = x\r
+       toString (ExprIdent x) = x\r
+       toString (ExprApp xs) = "(" +++ tostr [x\\x<-:xs] +++ ")"\r
+       where\r
+               tostr [] = ""\r
+               tostr [x] = toString x\r
+               tostr [x:xs] = toString x +++ " " +++ tostr xs\r
+       toString (ExprTuple xs) = "(" +++ tostr [x\\x<-:xs] +++ ")"\r
+       where\r
+               tostr [] = ""\r
+               tostr [x] = toString x\r
+               tostr [x:xs] = toString x +++ ", " +++ tostr xs\r
+       toString (ExprRecord name xs) = "{" +++ tostr [x\\x<-:xs] +++ "}"\r
+       where\r
+               tostr [] = ""\r
+               tostr [x] = toString x\r
+               tostr [x:xs] = toString x +++ ", " +++ tostr xs\r
+       toString (ExprField name expr) = name +++ "=" +++ toString expr\r
+\r
+               \r
+:: ParseState s =\r
+       { ps_input      :: !s                   // lex input\r
+       , ps_char       :: !Maybe Char  // unget char\r
+       , ps_tokens :: ![Token]         // unget tokens\r
+       }\r
+\r
+lexGetChar ps=:{ps_char=Nothing, ps_input}\r
+       # (mc, ps_input) = parseInput ps_input\r
+       = (mc, {ps & ps_input = ps_input})\r
+lexGetChar ps=:{ps_char} = (ps_char, {ps & ps_char = Nothing})\r
+\r
+lexUngetChar c ps=:{ps_char=Nothing} = {ps & ps_char = Just c}\r
+lexUngetChar c ps = abort "cannot unget\n"     \r
+\r
+isSpecialChar  :: !Char -> Bool\r
+isSpecialChar '~'      = True\r
+isSpecialChar '@'      = True\r
+isSpecialChar '#'      = True\r
+isSpecialChar '$'      = True\r
+isSpecialChar '%'      = True\r
+isSpecialChar '^'      = True\r
+isSpecialChar '?'      = True\r
+isSpecialChar '!'      = True\r
+isSpecialChar '+'      = True\r
+isSpecialChar '-'      = True\r
+isSpecialChar '*'      = True\r
+isSpecialChar '<'      = True\r
+isSpecialChar '>'      = True\r
+isSpecialChar '\\'     = True\r
+isSpecialChar '/'      = True\r
+isSpecialChar '|'      = True\r
+isSpecialChar '&'      = True\r
+isSpecialChar '='      = True\r
+isSpecialChar ':'      = True\r
+isSpecialChar '.'      = True\r
+isSpecialChar c                = False\r
+\r
+//----------------------------------------------------------------------------------           \r
+// lex input\r
+\r
+lexUngetToken token ps=:{ps_tokens} = {ps & ps_tokens = [token:ps_tokens]}\r
+\r
+lexGetToken ps=:{ps_tokens=[token:tokens]} = (token, {ps & ps_tokens = tokens})\r
+lexGetToken ps=:{ps_tokens=[]}\r
+       = lex ps\r
+where\r
+       lex s   \r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing  -> (TokenEnd, s)\r
+                       Just '\0' -> (TokenEnd, s)\r
+                       Just '(' -> (TokenOpenPar, s)\r
+                       Just ')' -> (TokenClosePar, s)\r
+                       Just '{' -> (TokenOpenCurly, s)\r
+                       Just '}' -> (TokenCloseCurly, s)\r
+                       Just '[' -> (TokenOpenList, s)\r
+                       Just ']' -> (TokenCloseList, s)\r
+                       Just ',' -> (TokenComma, s)\r
+                       Just '\'' -> lex_char 0 [] s\r
+                       Just '"'  -> lex_string 0 [] s\r
+                       Just '_' -> lex_ident 1 ['_'] s\r
+                       Just '`' -> lex_ident 1 ['`'] s\r
+                       Just '+'\r
+                               # (mc, s) = lexGetChar s\r
+                               -> case mc of\r
+                                       Nothing -> (TokenIdent "+", s)\r
+                                       Just c\r
+                                               | isDigit c\r
+                                                       -> lex_number +1 (lexUngetChar c s)\r
+                                               | otherwise\r
+                                                       -> lex_ident 1 ['+'] (lexUngetChar c s)\r
+                       Just '-'\r
+                               # (mc, s) = lexGetChar s\r
+                               -> case mc of\r
+                                       Nothing -> (TokenIdent "-", s)\r
+                                       Just c\r
+                                               | isDigit c\r
+                                                       -> lex_number -1 (lexUngetChar c s)\r
+                                               | otherwise\r
+                                                       -> lex_funny_ident 1 ['-'] (lexUngetChar c s) // PK\r
+       //                                              -> lex_ident 1 ['-'] (lexUngetChar c s)\r
+                       Just c\r
+                               | isSpace c\r
+                                       -> lex s \r
+                               | isDigit c\r
+                                       -> lex_number +1 (lexUngetChar c s)\r
+                               | isAlpha c\r
+                                       -> lex_ident 1 [c] s\r
+                               | isSpecialChar c\r
+                                       -> lex_funny_ident 1 [c] s\r
+                               | otherwise\r
+                                       -> (TokenError ("Unknown character " +++ toString c), s)\r
+\r
+       lex_digits s \r
+               = lex_digits_acc 0 [] s \r
+       lex_digits_acc num acc s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing \r
+                               -> (num, acc, s)\r
+                       Just c\r
+                               | isDigit c\r
+                                       -> lex_digits_acc (inc num) [digitToInt c:acc] s\r
+                               | otherwise \r
+                                       -> (num, acc, lexUngetChar c s)                                                                 \r
+\r
+       digits_to_int :: [Int] -> Int\r
+       digits_to_int [] = 0\r
+       digits_to_int [digit:digits] = digit + 10 * digits_to_int digits \r
+\r
+       digits_to_real :: [Int] -> Real \r
+       digits_to_real [] = 0.0\r
+       digits_to_real [digit:digits] = toReal digit + 10.0 * digits_to_real digits\r
+\r
+       lex_number sign s\r
+               #! (num_digits, digits, s) = lex_digits s\r
+               #! (mc, s) = lexGetChar s\r
+               = case mc of             \r
+                       Nothing -> (TokenInt (sign * digits_to_int digits), s)\r
+                       Just '.'\r
+                               -> lex_real_with_fraction (toReal sign) (digits_to_real digits) s\r
+                       Just 'E'\r
+                               #! real = toReal sign * digits_to_real digits \r
+                               -> lex_real_with_exp real s\r
+                       Just 'e'\r
+                               #! real = toReal sign * digits_to_real digits \r
+                               -> lex_real_with_exp real s\r
+                       Just c  \r
+                               -> (TokenInt (sign * digits_to_int digits), lexUngetChar c s)                                                                   \r
+\r
+       lex_real_with_fraction sign real s\r
+               #! (num_digits, digits, s) = lex_digits s\r
+               #! fraction = digits_to_real digits  / 10.0^ toReal num_digits  \r
+               #! real = sign * (real + fraction)      \r
+               #! (mc, s) = lexGetChar s\r
+               = case mc of             \r
+                       Nothing -> (TokenReal real, s)\r
+                       Just 'E'\r
+                               -> lex_real_with_exp real s\r
+                       Just 'e'\r
+                               -> lex_real_with_exp real s\r
+                       Just c  \r
+                               -> (TokenReal real, lexUngetChar c s)                                                                   \r
+\r
+       lex_real_with_exp real s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing -> (TokenReal real, s)\r
+                       Just '+' \r
+                               #! (num_digits, digits, s) = lex_digits s\r
+                               -> (TokenReal (real * 10.0 ^ digits_to_real digits), s)  \r
+                       Just '-' \r
+                               #! (num_digits, digits, s) = lex_digits s\r
+                               -> (TokenReal (real * 10.0 ^ (-1.0 * digits_to_real digits)), s)  \r
+                       Just c \r
+                               | isDigit c\r
+                                       #! (num_digits, digits, s) = lex_digits (lexUngetChar c s)\r
+                                       -> (TokenReal (real * 10.0 ^ digits_to_real digits), s)  \r
+                               | otherwise     \r
+                                       -> (TokenError "error in real constant", s)\r
+                                               \r
+       lex_ident num_chars acc_chars s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing -> (mktoken num_chars acc_chars, s)\r
+                       Just '_' -> lex_ident (inc num_chars) ['_':acc_chars] s\r
+                       Just '`' -> lex_ident (inc num_chars) ['`':acc_chars] s\r
+                       Just c  \r
+                               | isAlphanum c\r
+                                       -> lex_ident (inc num_chars) [c:acc_chars] s\r
+                               | otherwise  \r
+                                       -> (mktoken num_chars acc_chars, lexUngetChar c s)                                                                      \r
+       where\r
+               mktoken num_chars acc_chars\r
+                       = case mk_str num_chars acc_chars of\r
+                               "True"  -> TokenBool True\r
+                               "False" -> TokenBool False\r
+                               str             -> TokenIdent str                       \r
+\r
+       lex_funny_ident num_chars acc_chars s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing         -> (TokenIdent (mk_str num_chars acc_chars), s)\r
+                       Just c\r
+                               | isSpecialChar c\r
+                                       -> lex_funny_ident (inc num_chars) [c:acc_chars] s\r
+                               | otherwise             \r
+                                       -> (TokenIdent (mk_str num_chars acc_chars), lexUngetChar c s)                                                                  \r
+\r
+       lex_string num_chars acc_chars s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing -> (TokenError "error in string constant", s)\r
+                       Just '"' -> (TokenString (mk_str num_chars acc_chars), s)\r
+                       Just '\\' \r
+                               #! (mc, s) = lex_special_char s\r
+                               -> case mc of\r
+                                       Nothing -> (TokenError "error in string constant", s)\r
+                                       Just c -> lex_string (inc num_chars) [c:acc_chars] s\r
+                       Just c  -> lex_string (inc num_chars) [c:acc_chars] s\r
+\r
+\r
+       lex_char num_chars acc_chars s\r
+               # (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Nothing -> (TokenError "error in char constant", s)\r
+                       Just '\'' \r
+                               | num_chars == 1\r
+                                       -> (TokenChar (hd acc_chars), s)\r
+                               | num_chars == 0\r
+                                       -> (TokenError "char constant contains no characters ", s)\r
+                               | otherwise     \r
+                                       -> (TokenError "char constant contains more than one character", s)\r
+                       Just '\\' \r
+                               #! (mc, s) = lex_special_char s\r
+                               -> case mc of\r
+                                       Nothing -> (TokenError "error in char constant", s)\r
+                                       Just c -> lex_char (inc num_chars) [c:acc_chars] s\r
+                       Just c  -> lex_char (inc num_chars) [c:acc_chars] s\r
+\r
+       lex_special_char s \r
+               #! (mc, s) = lexGetChar s\r
+               = case mc of\r
+                       Just 'n' -> (Just '\n', s)\r
+                       Just 'r' -> (Just '\r', s)\r
+                       Just 'f' -> (Just '\f', s)\r
+                       Just 'b' -> (Just '\b', s)\r
+                       Just 't' -> (Just '\t', s)\r
+                       Just '\\' -> (Just '\\', s)\r
+                       Just '\'' -> (Just '\'', s)\r
+                       Just '\"' -> (Just '\"', s)\r
+                       Just '\0' -> (Just '\0', s)\r
+                       //Just '\x' -> abort "lex: hex char not implemented\n"\r
+                       //Just '\0' -> abort "lex: oct char not implemented\n"\r
+                       _ -> (mc, s)\r
+\r
+       mk_str num_chars acc_chars\r
+               # str = createArray num_chars ' '\r
+               = fill (dec num_chars) acc_chars str\r
+       where   \r
+               fill i [] str           = str\r
+               fill i [x:xs] str       = fill (dec i) xs {str & [i] = x}\r
+       \r
+\r
+//----------------------------------------------------------------------------------           \r
+// preparse input\r
+\r
+\r
+:: ParseEnv = PETop | PETuple | PEPar | PERecord | PEList\r
+\r
+preParse :: (ParseState s) -> (Expr, ParseState s) | ParseInput s\r
+preParse s \r
+       = parse_expr PETop s\r
+where\r
+       parse_expr env s\r
+               = parse_app env [] s\r
+       \r
+       parse_app env exprs s\r
+               #! (token, s) = lexGetToken s\r
+               = parse token env exprs s\r
+       where\r
+               parse TokenComma PETuple exprs  s       = (mkexpr exprs, lexUngetToken TokenComma s)\r
+               parse TokenComma PERecord exprs s       = (mkexpr exprs, lexUngetToken TokenComma s)\r
+               parse TokenComma PEList exprs   s       = (mkexpr exprs, lexUngetToken TokenComma s)\r
+               parse TokenComma PETop exprs s          = (ExprError "end of input expected instead of ,", s)\r
+               parse TokenComma PEPar exprs s          = (ExprError ") expected instead of ,", s)\r
+               parse TokenComma env exprs s            = abort "unknown env\n"\r
+\r
+               parse TokenClosePar PETuple     exprs s = (mkexpr exprs, lexUngetToken TokenClosePar s)\r
+               parse TokenClosePar PERecord exprs s = (ExprError "} expected instead of )", s)\r
+               parse TokenClosePar PEList exprs s  = (ExprError "] expected instead of )", s)\r
+               parse TokenClosePar PETop       exprs s = (ExprError "end of input expected instead of )", s)\r
+               parse TokenClosePar PEPar       exprs s = (mkexpr exprs, lexUngetToken TokenClosePar s)\r
+               parse TokenClosePar env exprs s         = abort "unknown env\n"\r
+\r
+               parse TokenCloseCurly PETuple   exprs s = (ExprError ") expected instead of }", s)\r
+               parse TokenCloseCurly PEList    exprs s = (ExprError "] expected instead of }", s)\r
+               parse TokenCloseCurly PERecord exprs s = (mkexpr exprs, lexUngetToken TokenCloseCurly s)\r
+               parse TokenCloseCurly PETop     exprs s = (ExprError "end of input expected instead of )", s)\r
+               parse TokenCloseCurly PEPar     exprs s = (mkexpr exprs, lexUngetToken TokenCloseCurly s)\r
+               parse TokenCloseCurly env exprs s       = abort "unknown env\n"\r
+\r
+               parse TokenCloseList PETuple exprs s    = (ExprError ") expected instead of ]", s)\r
+               parse TokenCloseList PERecord exprs s = (ExprError "} expected instead of ]", s)\r
+               parse TokenCloseList PEList exprs s = (mkexpr exprs, lexUngetToken TokenCloseList s)\r
+               parse TokenCloseList PETop      exprs s = (ExprError "end of input expected instead of )", s)\r
+               parse TokenCloseList PEPar      exprs s = (mkexpr exprs, lexUngetToken TokenCloseList s)\r
+               parse TokenCloseList env exprs s        = abort "unknown env\n"\r
+\r
+               parse TokenEnd PETuple exprs s          = (ExprError ") or, expected instead of end of input", s)\r
+               parse TokenEnd PERecord exprs s         = (ExprError "} or, expected instead of end of input", s)\r
+               parse TokenEnd PEList exprs s           = (ExprError "] or, expected instead of end of input", s)\r
+               parse TokenEnd PETop exprs s            = (mkexpr exprs, lexUngetToken TokenEnd s)\r
+               parse TokenEnd PEPar exprs s            = (ExprError ") expected instead of end of input",s)\r
+               parse TokenEnd env exprs s                      = abort "unknown env\n"\r
+       \r
+               parse (TokenInt x) env exprs s          = parse_app env [ExprInt x:exprs] s\r
+               parse (TokenBool x) env exprs s         = parse_app env [ExprBool x:exprs] s\r
+               parse (TokenReal x) env exprs s         = parse_app env [ExprReal x:exprs] s\r
+               parse (TokenChar x) env exprs s         = parse_app env [ExprChar x:exprs] s\r
+               parse (TokenString x) env exprs s       = parse_app env [ExprString x:exprs] s\r
+               parse (TokenIdent x) env exprs s        = parse_app env [ExprIdent x:exprs] s\r
+               parse TokenOpenPar env exprs s  \r
+                       # (expr, s)     = parse_par_expr s\r
+                       = case expr of\r
+                               ExprError err   -> (ExprError err, s)\r
+                               _                               ->  parse_app env [expr:exprs] s\r
+               parse TokenOpenCurly env exprs s\r
+                       # (expr, s) = parse_record_or_array s\r
+                       = case expr of\r
+                               ExprError err   -> (ExprError err, s)\r
+                               _                               ->  parse_app env [expr:exprs] s\r
+               parse TokenOpenList env exprs s \r
+                       # (expr, s) = parse_list s\r
+                       = case expr of\r
+                               ExprError err   -> (ExprError err, s)\r
+                               _                               ->  parse_app env [expr:exprs] s\r
+               parse (TokenError err) env exprs s \r
+                       = (ExprError ("lex error in parse_app: "  +++ err), s)          \r
+                               \r
+               parse token env exprs s \r
+                       = abort ("parse app - unknown token " +++ toString token)\r
+               \r
+               \r
+               mkexpr []               = ExprError "expression expected"\r
+               mkexpr [expr]   = expr\r
+               mkexpr exprs    = ExprApp {e\\e <- reverse exprs}\r
+\r
+       parse_par_expr s\r
+               #! (expr, s) = parse_expr PETuple s\r
+               = case expr of\r
+                       ExprError err -> (ExprError err, s)\r
+                       _\r
+                               #! (token, s) = lexGetToken s\r
+                               -> case token of\r
+                                       TokenClosePar -> (expr, s)\r
+                                       TokenComma -> parse_tuple [expr] (lexUngetToken token s)\r
+                                       _       -> (ExprError (", or ) expected, found " +++ toString token), s)\r
+                                                                                       \r
+       parse_tuple exprs s \r
+               #! (token, s) = lexGetToken s\r
+               = case token of\r
+                       TokenComma \r
+                               #! (expr, s) = parse_expr PETuple s\r
+                               -> case expr of\r
+                                       ExprError err -> (ExprError err, s)\r
+                                       _       -> parse_tuple [expr:exprs] s\r
+                       TokenClosePar \r
+                               -> (ExprTuple {e\\e<-reverse exprs}, s)\r
+                       _       \r
+                               -> (ExprError "parse tuple: , or ) expected", s)                \r
+\r
+       parse_list s\r
+               #! (token, s) = lexGetToken s\r
+               = case token of\r
+                       TokenCloseList \r
+                               -> (ExprList [], s)\r
+                       _  \r
+                               #! (expr, s) = parse_expr PEList (lexUngetToken token s)\r
+                               -> case expr of\r
+                                       ExprError err -> (ExprError (err +++ " ; parse list"), s)\r
+                                       _ -> parse_rest [expr] s\r
+       where\r
+               parse_rest exprs s              \r
+                       #! (token, s) = lexGetToken s\r
+                       = case token of\r
+                               TokenComma \r
+                                       #! (expr, s) = parse_expr PEList s\r
+                                       -> case expr of\r
+                                               ExprError err -> (ExprError err, s)\r
+                                               _       -> parse_rest [expr:exprs] s\r
+                               TokenCloseList \r
+                                       -> (ExprList (reverse exprs), s)\r
+                               _       \r
+                                       -> (ExprError "parse list: , or ] expected", s)                 \r
+\r
+               \r
+       parse_record_or_array s \r
+               #! (token, s) = lexGetToken s\r
+               = case token of\r
+                       TokenCloseCurly \r
+                               -> (ExprArray [], s)\r
+                       TokenIdent name\r
+                               #! (token, s) = lexGetToken s\r
+                               -> case token of\r
+                                       TokenIdent "="\r
+                                               #! (expr, s) = parse_expr PERecord s\r
+                                               -> parse_record Nothing [ExprField name expr] s\r
+                                       TokenIdent "|"\r
+                                               -> parse_record (Just ("_" +++ name)) [] (lexUngetToken TokenComma s)\r
+                                       _\r
+                                               #! (expr, s) = parse_expr PERecord \r
+                                                       (lexUngetToken (TokenIdent name) (lexUngetToken token s))\r
+                                               -> parse_array [expr] s\r
+                       _       \r
+                               #! (expr, s) = parse_expr PERecord (lexUngetToken token s)\r
+                               -> parse_array [expr] s\r
+       where\r
+               parse_record rec_name fields s\r
+                       #! (token, s) = lexGetToken s\r
+                       = case token of\r
+                               TokenCloseCurly \r
+                                       -> (ExprRecord rec_name {e\\e<- reverse fields}, s)\r
+                               TokenComma\r
+                                       #! (token, s) = lexGetToken     s\r
+                                       -> case token of\r
+                                               TokenIdent field_name\r
+                                                       #! (token, s) = lexGetToken     s\r
+                                                       -> case token of\r
+                                                               TokenIdent "=" \r
+                                                                       #! (expr, s) = parse_expr PERecord s\r
+                                                                       -> parse_record rec_name [ExprField field_name expr:fields] s\r
+                               _ -> (ExprError ("parse record failed on token " +++ toString token), s)                        \r
+\r
+               parse_array exprs s\r
+                       #! (token, s) = lexGetToken s\r
+                       = case token of\r
+                               TokenCloseCurly \r
+                                       -> (ExprArray (reverse exprs), s)\r
+                               TokenComma\r
+                                       #! (expr, s) = parse_expr PERecord s\r
+                                       -> parse_array [expr:exprs] s\r
+                               _ -> (ExprError ("parse array failed on token " +++ toString token), s)                 \r
+\r
+\r
+//----------------------------------------------------------------------------------           \r
+\r
+generic gParse a :: Expr -> Maybe a\r
+\r
+gParse{|Int|} (ExprInt x)                      = Just x \r
+gParse{|Int|} _                                                = Nothing\r
+\r
+gParse{|Char|} (ExprChar x)                    = Just x \r
+gParse{|Char|} _                                       = Nothing\r
+\r
+gParse{|Bool|} (ExprBool x)                    = Just x  \r
+gParse{|Bool|} _                                       = Nothing\r
+\r
+gParse{|Real|} (ExprReal x)                    = Just x  \r
+gParse{|Real|} _                                       = Nothing\r
+\r
+gParse{|String|} (ExprString x)                = Just x\r
+gParse{|String|} _                                     = Nothing \r
+\r
+gParse{|UNIT|} ExprUnit                        = Just UNIT\r
+gParse{|UNIT|} _                                       = Nothing \r
+\r
+gParse{|PAIR|} fx fy (ExprPair ex ey)  \r
+       = case fx ex of\r
+               Just x -> case fy ey of\r
+                       Just y                                  -> Just (PAIR x y)\r
+                       Nothing                                 -> Nothing\r
+               Nothing                                         -> Nothing\r
+gParse{|PAIR|} fx fy _                         = Nothing\r
+\r
+gParse{|EITHER|} fl fr expr    \r
+       = case fl expr of\r
+               Nothing                                         -> case fr expr of\r
+                       Nothing                                 -> Nothing\r
+                       Just x                                  -> Just (RIGHT x)\r
+               Just x                                          -> Just (LEFT x)        \r
+               \r
+gParse{|CONS of d|} parse_arg expr\r
+       | d.gcd_arity == 0      \r
+               = parse_nullary expr\r
+       | isEmpty d.gcd_fields\r
+               | is_tuple d.gcd_name\r
+                       = parse_tuple expr      \r
+               | otherwise\r
+                       = case d.gcd_prio of\r
+                               GenConsNoPrio                   \r
+                                       -> parse_nonfix expr\r
+                               GenConsPrio assoc prio  \r
+                                       -> parse_infix assoc prio expr                                          \r
+       | otherwise\r
+               = parse_record expr     \r
+where\r
+       mkprod []               = abort "mkprod\n"\r
+       mkprod [expr]   = expr\r
+       mkprod exprs    \r
+               # (xs, ys) = splitAt (length exprs / 2) exprs\r
+               = ExprPair (mkprod xs) (mkprod ys) \r
+       \r
+       parse_nullary (ExprIdent name)\r
+               | name == d.gcd_name\r
+                       = mapMaybe CONS (parse_arg ExprUnit)\r
+       parse_nullary _\r
+               = Nothing\r
+\r
+       parse_nonfix (ExprApp exprs)\r
+               = parse_nonfix1 exprs\r
+       parse_nonfix (ExprAppInInfix exprs _ _ _)\r
+               = parse_nonfix1 exprs\r
+       parse_nonfix _ \r
+               = Nothing\r
+\r
+       parse_nonfix1 exprs\r
+               #! size_exprs = size exprs\r
+               | size_exprs == d.gcd_arity + 1 && is_ident d.gcd_name exprs.[0]\r
+                       #! arg_exprs = [exprs.[i] \\ i <- [1 .. size_exprs - 1]]\r
+                       = mapMaybe CONS (parse_arg (mkprod arg_exprs))\r
+               | otherwise\r
+                       = Nothing\r
+       \r
+       is_ident wanted_name (ExprIdent name) = name == wanted_name\r
+       is_ident _ _ = False            \r
+\r
+       parse_tuple (ExprTuple exprs) \r
+               = mapMaybe CONS (parse_arg (mkprod [e\\e<-:exprs]))\r
+       parse_tuple expr = Nothing\r
+       \r
+       parse_record (ExprRecord rec_name exprs) \r
+               | check_name rec_name d.gcd_name\r
+                       = mapMaybe CONS (parse_arg (mkprod [e\\e<-:exprs]))\r
+                       = Nothing\r
+       where\r
+               check_name Nothing cons_name = True\r
+               check_name (Just rec_name) cons_name = rec_name == cons_name\r
+       parse_record expr = Nothing\r
+\r
+       parse_infix this_assoc this_prio (ExprApp exprs)\r
+               = parse_infix1 this_assoc this_prio exprs\r
+       parse_infix this_assoc this_prio (ExprAppInInfix exprs outer_assoc outer_prio branch)\r
+               | this_prio > outer_prio\r
+                       = parse_infix1 this_assoc this_prio exprs\r
+               | this_prio < outer_prio\r
+                       = Nothing\r
+               | otherwise\r
+                       = case (this_assoc, outer_assoc, branch) of\r
+                               (GenConsAssocLeft, GenConsAssocLeft, GenConsAssocLeft)\r
+                                       -> parse_infix1 this_assoc this_prio exprs\r
+                               (GenConsAssocRight, GenConsAssocRight, GenConsAssocRight)\r
+                                       -> parse_infix1 this_assoc this_prio exprs\r
+                               _ -> Nothing\r
+       parse_infix this_assoc this_prio expr\r
+               = Nothing\r
+               \r
+       parse_infix1 this_assoc this_prio exprs\r
+               #! size_exprs = size exprs\r
+               | size_exprs < 3 = Nothing\r
+               = case (case this_assoc of GenConsAssocLeft -> find_last; _ -> find_first) exprs of\r
+                       Nothing -> Nothing\r
+                       Just op_index\r
+                               #! left_arg  = mkarg GenConsAssocLeft {exprs.[i] \\ i <- [0 .. op_index - 1]}\r
+                               #! right_arg = mkarg GenConsAssocRight {exprs.[i] \\ i <- [op_index + 1 .. size_exprs - 1]}\r
+                               -> mapMaybe CONS (parse_arg (ExprPair left_arg right_arg))\r
+       where\r
+               mkarg branch exprs\r
+                       = case size exprs of\r
+                               0 -> abort "mkarg\n"\r
+                               1 -> exprs.[0]\r
+                               _ -> ExprAppInInfix exprs this_assoc this_prio branch\r
+       \r
+       find_last exprs \r
+               = find (size exprs - 2) exprs\r
+       where\r
+               find i exprs\r
+                       | i < 1\r
+                               = Nothing\r
+                       | otherwise     \r
+                               = case exprs.[i] of\r
+                                       ExprIdent s | s == d.gcd_name   -> Just i  \r
+                                       _                                                               -> find (dec i) exprs   \r
+       find_first exprs\r
+               = find 1 exprs\r
+       where\r
+               find i exprs\r
+                       | i >= size exprs - 1\r
+                               = Nothing\r
+                       | otherwise     \r
+                               = case exprs.[i] of\r
+                                       ExprIdent s | s == d.gcd_name   -> Just i  \r
+                                       _                                                               -> find (inc i) exprs   \r
+\r
+       is_tuple name \r
+               #! size_name = size name\r
+               = (size_name == 7 || size_name == 8)\r
+               && name.[0] == '_'\r
+               && name.[1] == 'T'\r
+               && name.[2] == 'u'\r
+               && name.[3] == 'p'\r
+               && name.[4] == 'l'\r
+               && name.[5] == 'e'\r
+               && isDigit name.[6]\r
+               && (size_name == 7 || isDigit name.[7])\r
+\r
+gParse{|FIELD of d|} parse_arg (ExprField name value) \r
+       | d.gfd_name == name\r
+               = mapMaybe FIELD (parse_arg value)\r
+               = Nothing\r
+gParse{|OBJECT|} parse_arg expr\r
+       = mapMaybe OBJECT (parse_arg expr)\r
+\r
+gParse{|[]|} parse_arg (ExprList exprs) \r
+       = maybeAll (map parse_arg exprs)\r
+gParse{|[]|} parse_arg _ = Nothing\r
+\r
+gParse{|{}|} parse_arg (ExprArray exprs)\r
+       = mapMaybe (\xs -> {x\\x<-xs}) (maybeAll (map parse_arg exprs)) \r
+gParse{|{}|} parse_arg _ = Nothing\r
+               \r
+gParse{|{!}|} parse_arg (ExprArray exprs)\r
+       = mapMaybe (\xs -> {x\\x<-xs}) (maybeAll (map parse_arg exprs))\r
+gParse{|{!}|} parse_arg _ = Nothing\r
+\r
+maybeAll []                    = Just []\r
+maybeAll [Nothing:_]   = Nothing\r
+maybeAll [Just x: mxs] \r
+       = case maybeAll mxs of\r
+               Nothing -> Nothing\r
+               Just xs -> Just [x:xs]  \r
+\r
+//----------------------------------------------------------------------------------           \r
+\r
+preParseInput :: s -> Expr | ParseInput s\r
+preParseInput input \r
+       # (expr, s) = preParse {ps_input=input, ps_char = Nothing, ps_tokens = [] }\r
+       = expr\r
+       \r
+preParseString :: String -> Expr\r
+preParseString str = preParseInput {si_pos = 0, si_str = str}\r
+\r
+preParseFile :: File -> Expr \r
+preParseFile file = preParseInput file\r
+\r
+parseString :: String -> Maybe a | gParse{|*|} a\r
+parseString str = gParse{|*|} (preParseString str)\r
+\r
+parseFile :: File -> Maybe a | gParse{|*|} a\r
+parseFile file = gParse{|*|} (preParseFile file)\r
+\r
+//Start = preParseString "{rec_field = A (B1, B2) (C D), rec_field2 = (X,Y)}"\r
+//Start = preParseString "123.456e1"\r
+//Start = preParseString "([1,2,3], [4,5,6])"\r
+//Start = preParseString "{A B D,X Y Z,I J K}"\r
+\r
+//----------------------------------------------------------------------------------           \r
+\r
+:: Tree a b = Tip a | Bin b (Tree a b) (Tree a b)\r
+:: T\r
+       = :+: infixl 2 T T\r
+       | :-: infixl 2 T T\r
+       | :*: infixl 3 T T\r
+       | :->: infixr 4 T T\r
+       | U\r
+\r
+:: Rec = { rec_x :: T, rec_y :: (.Tree Int Real, Real) }\r
+\r
+derive gParse (,), (,,), (,,,), Tree, T, Rec\r
+derive bimap Maybe, ParseState, []\r
+\r
+//Start :: Maybe T\r
+//Start = parseString "U :+: U :+: U"\r
+\r
+//Start :: Maybe (Tree Int Int)\r
+//Start = parseString "Bin 1 (Tip 2) (Tip 3)"\r
+\r
+//Start :: Maybe (Tree Int Int, Int)\r
+//Start = parseString "((Bin 1 (Tip (2)) (Tip 3), 1000))"\r
+\r
+//Start :: Maybe Rec\r
+//Start = parseString "{ Rec | rec_x = U :+: U :+: U, rec_y = (Bin 1.1 (Tip 2) (Tip 3), 1.09) }"\r
+\r
+//Start :: Maybe [Tree Int Int]\r
+//Start = parseString "[Bin 1 (Tip (2)) (Tip 3), Tip 100, Tip 200]" \r
+\r
+//Start = preParseString "1.23e12"\r
+\r
+/*\r
+Start :: *World -> (Maybe Rec, *World)\r
+Start w \r
+       #! (ok, f, w) = sfopen "test.txt" FReadText w\r
+       | not ok\r
+               = (abort "sfopen failed", w)\r
+               = (parseFile f, w)              \r
+*/
\ No newline at end of file