{-# OPTIONS_GHC -fglasgow-exts -funbox-strict-fields -fallow-overlapping-instances -fno-warn-orphans -fno-warn-incomplete-patterns -fallow-undecidable-instances -cpp #-}
{-|
Pugs Intermediate Language, version 2.
> And the Tree that was withered shall be renewed,
> And he shall plant it in the high places,
> And the City shall be blessed.
> Sing all ye people!
-}
module Pugs.PIL2 (
PIL_Environment(..),
PIL_Stmts(..), PIL_Stmt(..), PIL_Decl(..),
PIL_Expr(..), PIL_Literal(..), PIL_LValue(..),
TParam(..), TCxt(..), TEnv(..),
) where
import Pugs.AST hiding (Prim)
import Pugs.Internals hiding (get, put)
import Pugs.Types
import Emit.PIR
-- import DrIFT.XML
-- {-! global : Haskell2Xml !-}
{-! global : Perl5, JSON, YAML !-}
{-|
The plan here is to first compile the environment (subroutines,
statements, etc.) to an abstract syntax tree ('PIL' -- Pugs Intermediate
Language) using the 'compile' function and 'Compile' class.
- Unify the Apply and Bind forms into method calls.
Apply becomes .postcircumfix:<( )>
Bind becomes .infix:<:=>
- Compile-time object initiation built with opaque object binders
- A PIL tree is merely an (unordered!) set of static declarations;
the responsibility of calling the main function -- let's call it &{''}
just for fun -- resides on the runtime.
- Anonymous closures -- should they be lambda-lifted and given ANON
names? If yes this gives us flexibility over CSE (common shared expression)
optimization, but this may be BDUF. No λ lifting for now.
- Okay, time to try a simple definition.
[SRC] say "Hello, World!"
[PIL] SigList.new('&').infix:<:=>(
Code.new(
body => [|
::?MY.postcircumfix<{ }>('&say')
.postcircumfix<( )>(Str.new('Hello World'))
|]
... # other misc attributes
)
)
-- Compile time analysis of &say is needed here.
-- We want to allow possibility of MMD (note _open_ pkgs by default)
so there needs to be a generic form.
-- Static binding performed as another optimization pass.
-- Predefined objects (_always_ bound to the same thing in compiler)
::?MY -- current lexical scope
::?OUR -- current package scope
Symbol resolution (static vs dynamic lookup) is to be done at
pass-1 for PIL2. The '&say' below is _definitely_ dynamic.
Or is it? Why? Because @\@Larry@ mandates 'multi &*say' instead
of a more restricted form of ::* as a default lexical scope
that closes over the toplevel program. Maybe pursue a ruling
toward the more static definition, otherwise all builtins become
_slower_ to infer than userdefined code, which is Just Not Right.
-- String construction -- handled like perl5 using string overloading
Ask @\@Larry@ for ruling over constant creation and propagation rules.
(probably: use a macro if you'd like to change)
so, safe to assume a prim form in PIL level.
-- We _really_ need a quasiquoting notation for macro generation;
introduce moral equivalent of [|...|] in PIL form, probably just an
"AST" node. (in CLR they call it System.Reflection.Expression)
-- problem with this is it's a closed set; if we are to extend AST
on the compiler level --
-- nah, we aren't bootstrapping yet. KISS.
-- This is a very imperative view; the runtime would be carrying
instructions of populating the ObjSpace (Smalltalk, Ruby-ish)
rather than fitting an AST into a lexical evaluator environment
(LISP, Scheme-ish)
-- Need better annotator for inferrence to work, esp. now it's
populated with redundant .postcircumfix calls. OTOH, they
can be assumed to be closed under separate-compilation regime,
so we eventually regain the signature. But it'd be much slower
than the current PIL1. Oy vey.
-- OTOH, refactor into a Callable role and introduce .apply?
This is integral's (sensible) suggestion, but we don't have a
Role system working yet, so why bother.
-}
data PIL_Environment = PIL_Environment
{ pilGlob :: [PIL_Decl]
, pilMain :: PIL_Stmts
}
deriving (Show, Eq, Ord, Typeable)
data PIL_Stmts = PNil
| PStmts
{ pStmt :: !PIL_Stmt
, pStmts :: !PIL_Stmts
}
| PPad
{ pScope :: !Scope
, pSyms :: ![(VarName, PIL_Expr)]
, pStmts :: !PIL_Stmts
}
deriving (Show, Eq, Ord, Typeable)
data PIL_Stmt = PNoop | PStmt { pExpr :: !PIL_Expr } | PPos
{ pPos :: !Pos
, pExp :: !Exp
, pNode :: !PIL_Stmt
}
deriving (Show, Eq, Ord, Typeable)
data PIL_Expr
= PRawName { pRawName :: !VarName }
| PExp { pLV :: !PIL_LValue }
| PLit { pLit :: !PIL_Literal }
| PThunk { pThunk :: !PIL_Expr }
| PCode
{ pType :: !SubType
, pParams :: ![TParam]
, pLValue :: !Bool
, pIsMulti :: !Bool
, pBody :: !PIL_Stmts
}
deriving (Show, Eq, Ord, Typeable)
data PIL_Decl = PSub
{ pSubName :: !SubName
, pSubType :: !SubType
, pSubParams :: ![TParam]
, pSubLValue :: !Bool
, pSubIsMulti :: !Bool
, pSubBody :: !PIL_Stmts
}
deriving (Show, Eq, Ord, Typeable)
data PIL_Literal = PVal { pVal :: Val }
deriving (Show, Eq, Ord, Typeable)
data PIL_LValue = PVar { pVarName :: !VarName }
| PApp
{ pCxt :: !TCxt
, pFun :: !PIL_Expr
, pInv :: !(Maybe PIL_Expr)
, pArgs :: ![PIL_Expr]
}
| PAssign
{ pLHS :: ![PIL_LValue]
, pRHS :: !PIL_Expr
}
| PBind
{ pLHS :: ![PIL_LValue]
, pRHS :: !PIL_Expr
}
deriving (Show, Eq, Ord, Typeable)
data TParam = MkTParam
{ tpParam :: !Param
, tpDefault :: !(Maybe (PIL_Expr))
}
deriving (Show, Eq, Ord, Typeable)
data TCxt
= TCxtVoid | TCxtLValue !Type | TCxtItem !Type | TCxtSlurpy !Type
| TTailCall !TCxt
deriving (Show, Eq, Ord, Typeable)
data TEnv = MkTEnv
{ tLexDepth :: !Int -- ^ Lexical scope depth
, tTokDepth :: !Int -- ^ Exp nesting depth
, tCxt :: !TCxt -- ^ Current context
, tReg :: !(TVar (Int, String))-- ^ Register name supply
, tLabel :: !(TVar Int) -- ^ Label name supply
}
deriving (Show, Eq, Ord, Typeable)