haskell - Getting a <<loop>> when implementing block-visibility in a type-checker -


i'm writing simple type-checker simple imperative language, , i'm stuck kind of output:

testchecker: <<loop>> 

i have alread read this question, know must doing wrong circular reference. i'm pretty sure problem in following function, responsible checking block of statements:

checkgroup :: environ -> [prog] -> (state, environ, [string]) checkgroup env progs = (finalstate, finalenv, messages)     (finalstate, finalenv, messages) = foldl checksingleprog (ok, empty, []) progs           checksingleprog (s, e, msg) prog = (ress, mergeenv e e', mess)               (s', e', msg') = checkprog (mergeenv' env finalenv) prog                     mess = msg ++ msg'                     ress = if s == err || s' == err err else ok 

note the:

checkprog (mergeenv' env finalenv) prog 

where checkprog uses environment merging of environment of father of group plus environment generated whole group.

(edit: yes know finalenv part of output of call checkprog. that's point of question. know can done, don't understand i'm doing wrong trick.)

the mergeenv' function union between environments (it preferes right argument, opposed m.union), keeping left-argument's variables. it's definition is:

-- variables, functions, labels [for goto] type environ = (m.map string type, m.map string type, s.set string)  mergeenv' :: environ -> environ -> environ mergeenv' env1 env2 = (fst' env1,                        m.union (snd' env2) (snd' env1),                        s.union (thr' env2) (thr' env1)) 

(the mergeenv (no apos @ end) 3 unions.)

the prog type type of statements (e.g. if, for, group etc.) state type either ok or err, signal successful , unsuccessful checking.

what i'm trying achieve have block-visibility function definitions (and labels) , forward visibility variables, without doing 2 different runs.

if change:

(mergeenv' env finalenv) 

to:

env 

everything runs "fine", visibility forward everything.

i know it's possible achieve want in way similar i'm trying (i got idea professor of languages , compilers), seems i'm doing wrong merging of environments.

am doing wrong? or should work , problem hidden somewhere else in type-checker?


here's minimal working example demonstrates problem. it's still 180 lines:

module main   import qualified data.map m   data prog = group [prog]           | fdecl type string [(type, string)] prog           | simple simple     deriving (eq, show)  data simple = rexp rexp             | vdecl type string rexp             | return rexp     deriving (eq, show)   data rexp = call string [rexp]           | lexp lexp           | const const     deriving(eq, show)   data lexp = ident string     deriving (eq, show)  data const = integer integer     deriving (eq, show)   data type = func type [type]           | int           | error     deriving (eq, show)     compatible :: type -> type -> bool compatible _ error = true compatible x y | x == y = true compatible (func ty types) (func ty' types') = compatible ty ty' && , (zipwith compatible types types') compatible _ _ = false     type environ = (m.map string type, m.map string type)  empty :: environ empty = (m.empty, m.empty)   hasvar :: environ -> string -> bool hasvar env var = m.member var $ fst env  getvartype :: environ -> string -> type getvartype env var = fst env m.! var  putvar :: environ -> string -> type -> environ putvar env var ty = (m.insert var ty $ fst env, snd env)  hasfunc :: environ -> string -> bool hasfunc env func = m.member func $ snd env  getfunctype :: environ -> string -> type getfunctype env func = snd env m.! func  putfunc :: environ -> string -> type -> environ putfunc env func ty = (fst env, m.insert func ty $ snd env)  vars :: environ -> m.map string type vars = fst  funcs :: environ -> m.map string type funcs = snd   mergeenv :: environ -> environ -> environ mergeenv env1 env2 = (m.union (fst env2) (fst env1),                       m.union (snd env2) (snd env1))   mergeenv' :: environ -> environ -> environ mergeenv' env1 env2 = (fst env1,                        m.union (snd env2) (snd env1))    data state = ok | err     deriving (eq, show)      checkprog :: environ -> prog -> (state, environ, [string]) checkprog env prog = case prog of                           group progs -> checkgroup env progs                           fdecl rettype name params body -> checkfdecl env rettype name params body                           simple simple -> checksimple env simple  checksimple :: environ -> simple -> (state, environ, [string]) checksimple env simple = case simple of                               rexp expr -> checkexpr expr                               vdecl typ name expr -> checkvdecl env typ name expr                               return expr -> (ok, empty, [])     checkexpr expr = let (t, msg) = checkrexpr env expr                            in if t == error                                  (err, empty, msg)                                  else (ok, empty, msg)  checkgroup :: environ -> [prog] -> (state, environ, [string]) checkgroup env progs = (finalstate, finalenv, messages)     (finalstate, finalenv, messages) = foldl checksingleprog (ok, empty, []) progs           checksingleprog (s, e, msg) prog = (resstate, mergeenv e e', message)               (s', e', msg') = checkprog (mergeenv' env finalenv) prog                     message = msg ++ msg'                     resstate = if s == err || s' == err err else ok  checkfdecl :: environ -> type -> string -> [(type, string)] -> prog -> (state, environ, [string]) checkfdecl env rty name params body = (s, putfunc empty name funtype, msg)     funtype = func rty [t | (t,_) <- params]           paramenv = (m.fromlist [(x, ty) | (ty, x) <- params], m.empty)           baseenv = mergeenv paramenv (putfunc env name funtype)           (s, e', msg) = checkprog baseenv body  checkvdecl :: environ -> type -> string -> rexp -> (state, environ, [string]) checkvdecl env ty name expr = if t == error                                  (err, empty, msg)                                  else if compatible t ty                                          (ok, putvar empty name ty, msg)                                          else (err, empty, msg ++ errmsg)     (t, msg) = checkrexpr env expr           errmsg = ["incompatible assignment of type: " ++ show t ++ " variable of type: " ++ show ty]   checkrexpr env expr = case expr of                            const _-> (int, [])                            lexp lexp -> checklexpr env lexp                            call name params -> checkcall env name params  checklexpr env lexp = if env `hasvar` name                          (getvartype env name, [])                          else (error, ["undefined identifier: " ++ name])     (ident name) = lexp  checkcall env name params = if not $ env `hasfunc` name                                (error, ["undefined function: " ++ name])                                else let (func retty paramsty) = getfunctype env name                                     in if length params /= length paramsty                                           (error, ["wrong number of arguments."])                                           else if , $ zipwith checkparam paramsty params                                                   (retty, [])                                                   else (error, ["wrong type argument."])     checkparam typ param = let (t, _) = checkrexpr env param                                  in compatible t typ    {- def f() -> int:     return g()  def g() -> int:     return 1  f() -}  testprog = group [fdecl int "f" [] $ group [simple $ return $ call "g" []],                   fdecl int "g" [] $ group [simple $ return $ const $ integer 1],                   simple $ rexp $ call "f" []]   main =     let (s,e,msg) = checkprog empty testprog     if s == ok        putstrln "correct!"        else putstrln "error!"     putstrln $ concatmap (++ "\n") msg 

you're defining finalenv in terms of foldl , you're defining foldl, via checkprog, in terms of finalenv seems algorithm wrong.


Comments

Popular posts from this blog

c# - How to get the current UAC mode -

postgresql - Lazarus + Postgres: incomplete startup packet -

javascript - Ajax jqXHR.status==0 fix error -