{----
 - Syntax.hs - Abstract syntax and abstract syntax printing logic
 -          for the noodle programming language
 ----
 - Author: Jesse Rudolph <jesse.rudolph@gmail.com>
 - See LICENSE for licensing details
 ----------------------------------------------------------------- -}
module Language.Noodle.Syntax where

import Data.List
import Data.Unique

-- this is mostly self documenting.

data Decl = IntThunk String Comp
          | IntFun Pattern String Comp
          | IntOp Pattern String Pattern Comp
          | IntMod String Decls


data Decls = Decls {toDecList :: [Decl]}


data Comp = In Decls Comp
          | With Comp Comp
          | PatMatch Pattern Comp Comp
          | Handler Comp Comp
          | ExprComp Expr


data Expr = ExprApp Expr Expr
          | ExprOp Expr String Expr
          | ModRef String
          | Lit (Literal Comp)


instance Show Expr where
    show (ExprApp arg f) = "(" ++ show arg ++ " " ++ show f ++ ")"
    show (ExprOp c1 op c2)   = "(" ++ show c1 ++ op ++ show c2 ++ ")"
    show (Lit l)         = show l
    show (ModRef s)      = "." ++ s
    show _               = "<printing not implemented>"


instance Show Comp where
    show (In d c)     =  "in " ++ show c ++ ";\n" ++ show d
    show (With c c2)  = "with " ++ show c ++ ";\n" ++ show c2
    show (PatMatch p c c2)
                      = show p ++ "=" ++ show c ++ ";\n" ++ show c2
    show (ExprComp e) = show e
    show _            = "<printing not implemented>"


instance Show Decl where
    show (IntThunk n c)  = n ++ " := " ++ show c
    show (IntFun p s c)  = show p ++ " " ++ s ++ " := " ++ show c
    show (IntOp p s p2 c)
                         = show p ++ " " ++ s ++ " " ++ show p2 ++ " := " ++ show c
    show (IntMod s d)    = "module " ++ s ++ " " ++ show d
    show _               = "<printing not implemented>"


instance Show Decls where
    show (Decls ds)      = "{ " ++ sdecls ds ++ " }" where
        sdecls [d] = show d
        sdecls ds
          = concat $ intersperse ".\n" $ map show ds
    show _               = "<printing not implemented>"


-- clauses are a lexical pattern, not a syntactic pattern, so we need a special function to keep from
-- having multiple implementations of their display logic all over the place.
showClause :: (String,String) -> String
showClause (a,b) = a ++ " := " ++ b


newtype Pattern = Pat (Literal Pattern)


data Literal a = Numb Integer
               | Ident String
               | Symb String
               | StrLit String
               | ProdLit a a [a]
               | Abs a
               | Paren a


instance Show Pattern where
    show (Pat l) = show l
    show _       = "<printing not implemented>"


instance (Show a) => Show (Literal a) where
    show (Numb n)   = show n
    show (Ident s)  = s
    show (Paren a)  = show a
    show (StrLit s) = show s
    show (Symb s)   = s
    show _          = "<printing not implemented>"