forked from GitHub/gf-core
reintroduce the compiler API
This commit is contained in:
483
src/compiler/api/GF/Grammar/Grammar.hs
Normal file
483
src/compiler/api/GF/Grammar/Grammar.hs
Normal file
@@ -0,0 +1,483 @@
|
||||
----------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : Grammar
|
||||
-- Maintainer : AR
|
||||
-- Stability : (stable)
|
||||
-- Portability : (portable)
|
||||
--
|
||||
-- > CVS $Date: 2005/04/21 16:22:20 $
|
||||
-- > CVS $Author: bringert $
|
||||
-- > CVS $Revision: 1.8 $
|
||||
--
|
||||
-- GF source abstract syntax used internally in compilation.
|
||||
--
|
||||
-- AR 23\/1\/2000 -- 30\/5\/2001 -- 4\/5\/2003
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module GF.Grammar.Grammar (
|
||||
-- ** Grammar modules
|
||||
Grammar, ModuleName, Module, ModuleInfo(..),
|
||||
SourceGrammar, SourceModInfo, SourceModule,
|
||||
ModuleType(..),
|
||||
emptyGrammar, mGrammar, modules, prependModule, moduleMap,
|
||||
|
||||
MInclude (..), OpenSpec(..),
|
||||
extends, isInherited, inheritAll,
|
||||
openedModule, allDepsModule, partOfGrammar, depPathModule,
|
||||
allExtends, allExtendsPlus, --searchPathModule,
|
||||
|
||||
lookupModule,
|
||||
isModAbs, isModRes, isModCnc,
|
||||
sameMType, isCompilableModule, isCompleteModule,
|
||||
allAbstracts, greatestAbstract, allResources,
|
||||
greatestResource, allConcretes, allConcreteModules,
|
||||
abstractOfConcrete,
|
||||
|
||||
ModuleStatus(..),
|
||||
|
||||
-- ** Judgements
|
||||
Info(..),
|
||||
-- ** Terms
|
||||
Term(..),
|
||||
Type,
|
||||
Cat,
|
||||
Fun,
|
||||
QIdent,
|
||||
BindType(..),
|
||||
Patt(..),
|
||||
TInfo(..),
|
||||
Label(..),
|
||||
MetaId,
|
||||
Hypo,
|
||||
Context,
|
||||
Equation,
|
||||
Labelling,
|
||||
Assign,
|
||||
Case,
|
||||
LocalDef,
|
||||
Param,
|
||||
Altern,
|
||||
Substitution,
|
||||
varLabel, tupleLabel, linLabel, theLinLabel,
|
||||
ident2label, label2ident,
|
||||
-- ** Source locations
|
||||
Location(..), L(..), unLoc, noLoc, ppLocation, ppL,
|
||||
|
||||
-- ** PMCFG
|
||||
LIndex,LVar,LParam(..),PArg(..),Symbol(..),Production(..)
|
||||
) where
|
||||
|
||||
import GF.Infra.Ident
|
||||
import GF.Infra.Option ---
|
||||
import GF.Infra.Location
|
||||
|
||||
import GF.Data.Operations
|
||||
|
||||
import PGF2(BindType(..))
|
||||
import PGF2.Transactions(SeqId,LIndex,LVar,LParam(..),PArg(..),Symbol(..),Production(..))
|
||||
|
||||
import Data.Array.IArray(Array)
|
||||
import Data.Array.Unboxed(UArray)
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Sequence as Seq
|
||||
import GF.Text.Pretty
|
||||
|
||||
|
||||
-- | A grammar is a self-contained collection of grammar modules
|
||||
data Grammar = MGrammar {
|
||||
moduleMap :: Map.Map ModuleName ModuleInfo,
|
||||
modules :: [Module]
|
||||
}
|
||||
|
||||
-- | Modules
|
||||
type Module = (ModuleName, ModuleInfo)
|
||||
|
||||
data ModuleInfo = ModInfo {
|
||||
mtype :: ModuleType,
|
||||
mstatus :: ModuleStatus,
|
||||
mflags :: Options,
|
||||
mextend :: [(ModuleName,MInclude)],
|
||||
mwith :: Maybe (ModuleName,MInclude,[(ModuleName,ModuleName)]),
|
||||
mopens :: [OpenSpec],
|
||||
mexdeps :: [ModuleName],
|
||||
msrc :: FilePath,
|
||||
mseqs :: Maybe (Seq.Seq [Symbol]),
|
||||
jments :: Map.Map Ident Info
|
||||
}
|
||||
|
||||
type SourceGrammar = Grammar
|
||||
type SourceModule = Module
|
||||
type SourceModInfo = ModuleInfo
|
||||
|
||||
instance HasSourcePath ModuleInfo where sourcePath = msrc
|
||||
|
||||
-- | encoding the type of the module
|
||||
data ModuleType =
|
||||
MTAbstract
|
||||
| MTResource
|
||||
| MTConcrete ModuleName
|
||||
| MTInterface
|
||||
| MTInstance (ModuleName,MInclude)
|
||||
deriving (Eq,Show)
|
||||
|
||||
data MInclude = MIAll | MIOnly [Ident] | MIExcept [Ident]
|
||||
deriving (Eq,Show)
|
||||
|
||||
extends :: ModuleInfo -> [ModuleName]
|
||||
extends = map fst . mextend
|
||||
|
||||
isInherited :: MInclude -> Ident -> Bool
|
||||
isInherited c i = case c of
|
||||
MIAll -> True
|
||||
MIOnly is -> elem i is
|
||||
MIExcept is -> notElem i is
|
||||
|
||||
inheritAll :: ModuleName -> (ModuleName,MInclude)
|
||||
inheritAll i = (i,MIAll)
|
||||
|
||||
data OpenSpec =
|
||||
OSimple ModuleName
|
||||
| OQualif ModuleName ModuleName
|
||||
deriving (Eq,Show)
|
||||
|
||||
data ModuleStatus =
|
||||
MSComplete
|
||||
| MSIncomplete
|
||||
deriving (Eq,Ord,Show)
|
||||
|
||||
openedModule :: OpenSpec -> ModuleName
|
||||
openedModule o = case o of
|
||||
OSimple m -> m
|
||||
OQualif _ m -> m
|
||||
|
||||
-- | initial dependency list
|
||||
depPathModule :: ModuleInfo -> [OpenSpec]
|
||||
depPathModule m = fors m ++ exts m ++ mopens m
|
||||
where
|
||||
fors m =
|
||||
case mtype m of
|
||||
MTConcrete i -> [OSimple i]
|
||||
MTInstance (i,_) -> [OSimple i]
|
||||
_ -> []
|
||||
exts m = map OSimple (extends m)
|
||||
|
||||
-- | all dependencies
|
||||
allDepsModule :: Grammar -> ModuleInfo -> [OpenSpec]
|
||||
allDepsModule gr m = iterFix add os0 where
|
||||
os0 = depPathModule m
|
||||
add os = [m | o <- os, Just n <- [lookup (openedModule o) mods],
|
||||
m <- depPathModule n]
|
||||
mods = modules gr
|
||||
|
||||
-- | select just those modules that a given one depends on, including itself
|
||||
partOfGrammar :: Grammar -> Module -> Grammar
|
||||
partOfGrammar gr (i,m) = mGrammar [mo | mo@(j,_) <- mods, elem j modsFor]
|
||||
where
|
||||
mods = modules gr
|
||||
modsFor = (i:) $ map openedModule $ allDepsModule gr m
|
||||
|
||||
-- | all modules that a module extends, directly or indirectly, with restricts
|
||||
allExtends :: Grammar -> ModuleName -> [Module]
|
||||
allExtends gr m =
|
||||
case lookupModule gr m of
|
||||
Ok mi -> (m,mi) : concatMap (allExtends gr . fst) (mextend mi)
|
||||
_ -> []
|
||||
|
||||
-- | the same as 'allExtends' plus that an instance extends its interface
|
||||
allExtendsPlus :: Grammar -> ModuleName -> [ModuleName]
|
||||
allExtendsPlus gr i =
|
||||
case lookupModule gr i of
|
||||
Ok m -> i : concatMap (allExtendsPlus gr) (exts m)
|
||||
_ -> []
|
||||
where
|
||||
exts m = extends m ++ [j | MTInstance (j,_) <- [mtype m]]
|
||||
|
||||
-- -- | initial search path: the nonqualified dependencies
|
||||
-- searchPathModule :: ModuleInfo -> [ModuleName]
|
||||
-- searchPathModule m = [i | OSimple i <- depPathModule m]
|
||||
|
||||
prependModule :: Grammar -> Module -> Grammar
|
||||
prependModule (MGrammar mm ms) im@(i,m) = MGrammar (Map.insert i m mm) (im:ms)
|
||||
|
||||
emptyGrammar = mGrammar []
|
||||
|
||||
mGrammar :: [Module] -> Grammar
|
||||
mGrammar ms = MGrammar (Map.fromList ms) ms
|
||||
|
||||
|
||||
-- | we store the module type with the identifier
|
||||
|
||||
abstractOfConcrete :: ErrorMonad m => Grammar -> ModuleName -> m ModuleName
|
||||
abstractOfConcrete gr c = do
|
||||
n <- lookupModule gr c
|
||||
case mtype n of
|
||||
MTConcrete a -> return a
|
||||
_ -> raise $ render ("expected concrete" <+> c)
|
||||
|
||||
lookupModule :: ErrorMonad m => Grammar -> ModuleName -> m ModuleInfo
|
||||
lookupModule gr m = case Map.lookup m (moduleMap gr) of
|
||||
Just i -> return i
|
||||
Nothing -> raise $ render ("unknown module" <+> m <+> "among" <+> hsep (map fst (modules gr)))
|
||||
|
||||
isModAbs :: ModuleInfo -> Bool
|
||||
isModAbs m =
|
||||
case mtype m of
|
||||
MTAbstract -> True
|
||||
_ -> False
|
||||
|
||||
isModRes :: ModuleInfo -> Bool
|
||||
isModRes m =
|
||||
case mtype m of
|
||||
MTResource -> True
|
||||
MTInterface -> True ---
|
||||
MTInstance _ -> True
|
||||
_ -> False
|
||||
|
||||
isModCnc :: ModuleInfo -> Bool
|
||||
isModCnc m =
|
||||
case mtype m of
|
||||
MTConcrete _ -> True
|
||||
_ -> False
|
||||
|
||||
sameMType :: ModuleType -> ModuleType -> Bool
|
||||
sameMType m n =
|
||||
case (n,m) of
|
||||
(MTConcrete _, MTConcrete _) -> True
|
||||
|
||||
(MTInstance _, MTInstance _) -> True
|
||||
(MTInstance _, MTResource) -> True
|
||||
(MTInstance _, MTConcrete _) -> True
|
||||
|
||||
(MTInterface, MTInstance _) -> True
|
||||
(MTInterface, MTResource) -> True -- for reuse
|
||||
(MTInterface, MTAbstract) -> True -- for reuse
|
||||
(MTInterface, MTConcrete _) -> True -- for reuse
|
||||
|
||||
(MTResource, MTInstance _) -> True
|
||||
(MTResource, MTConcrete _) -> True -- for reuse
|
||||
|
||||
_ -> m == n
|
||||
|
||||
-- | don't generate code for interfaces and for incomplete modules
|
||||
isCompilableModule :: ModuleInfo -> Bool
|
||||
isCompilableModule m =
|
||||
case mtype m of
|
||||
MTInterface -> False
|
||||
_ -> mstatus m == MSComplete
|
||||
|
||||
-- | interface and "incomplete M" are not complete
|
||||
isCompleteModule :: ModuleInfo -> Bool
|
||||
isCompleteModule m = mstatus m == MSComplete && mtype m /= MTInterface
|
||||
|
||||
|
||||
-- | all abstract modules sorted from least to most dependent
|
||||
allAbstracts :: Grammar -> [ModuleName]
|
||||
allAbstracts gr =
|
||||
case topoTest [(i,extends m) | (i,m) <- modules gr, mtype m == MTAbstract] of
|
||||
Left is -> is
|
||||
Right cycles -> error $ render ("Cyclic abstract modules:" <+> vcat (map hsep cycles))
|
||||
|
||||
-- | the last abstract in dependency order (head of list)
|
||||
greatestAbstract :: Grammar -> Maybe ModuleName
|
||||
greatestAbstract gr =
|
||||
case allAbstracts gr of
|
||||
[] -> Nothing
|
||||
as -> return $ last as
|
||||
|
||||
-- | all resource modules
|
||||
allResources :: Grammar -> [ModuleName]
|
||||
allResources gr = [i | (i,m) <- modules gr, isModRes m || isModCnc m]
|
||||
|
||||
-- | the greatest resource in dependency order
|
||||
greatestResource :: Grammar -> Maybe ModuleName
|
||||
greatestResource gr =
|
||||
case allResources gr of
|
||||
[] -> Nothing
|
||||
mo:_ -> Just mo ---- why not last as in Abstract? works though AR 24/5/2008
|
||||
|
||||
-- | all concretes for a given abstract
|
||||
allConcretes :: Grammar -> ModuleName -> [ModuleName]
|
||||
allConcretes gr a =
|
||||
[i | (i, m) <- modules gr, mtype m == MTConcrete a, isCompleteModule m]
|
||||
|
||||
-- | all concrete modules for any abstract
|
||||
allConcreteModules :: Grammar -> [ModuleName]
|
||||
allConcreteModules gr =
|
||||
[i | (i, m) <- modules gr, MTConcrete _ <- [mtype m], isCompleteModule m]
|
||||
|
||||
|
||||
-- | the constructors are judgements in
|
||||
--
|
||||
-- - abstract syntax (/ABS/)
|
||||
--
|
||||
-- - resource (/RES/)
|
||||
--
|
||||
-- - concrete syntax (/CNC/)
|
||||
--
|
||||
-- and indirection to module (/INDIR/)
|
||||
data Info =
|
||||
-- judgements in abstract syntax
|
||||
AbsCat (Maybe (L Context)) -- ^ (/ABS/) context of a category
|
||||
| AbsFun (Maybe (L Type)) (Maybe Int) (Maybe [L Equation]) (Maybe Bool) -- ^ (/ABS/) type, arrity and definition of a function
|
||||
|
||||
-- judgements in resource
|
||||
| ResParam (Maybe (L [Param])) (Maybe ([Term],Int)) -- ^ (/RES/) The second argument is list of all possible values
|
||||
-- and its precomputed length.
|
||||
| ResValue (L Type) Int -- ^ (/RES/) to mark parameter constructors for lookup.
|
||||
-- The second argument is the offset into the list of all values
|
||||
-- where that constructor appears first.
|
||||
| ResOper (Maybe (L Type)) (Maybe (L Term)) -- ^ (/RES/)
|
||||
|
||||
| ResOverload [ModuleName] [(L Type,L Term)] -- ^ (/RES/) idents: modules inherited
|
||||
|
||||
-- judgements in concrete syntax
|
||||
| CncCat (Maybe (L Type)) (Maybe (L Term)) (Maybe (L Term)) (Maybe (L Term)) (Maybe ([Production],[Production])) -- ^ (/CNC/) lindef ini'zed,
|
||||
| CncFun (Maybe ([Ident],Ident,Context,Type)) (Maybe (L Term)) (Maybe (L Term)) (Maybe [Production]) -- ^ (/CNC/) type info added at 'TC'
|
||||
|
||||
-- indirection to module Ident
|
||||
| AnyInd Bool ModuleName -- ^ (/INDIR/) the 'Bool' says if canonical
|
||||
deriving Show
|
||||
|
||||
type Type = Term
|
||||
type Cat = QIdent
|
||||
type Fun = QIdent
|
||||
|
||||
type QIdent = (ModuleName,Ident)
|
||||
|
||||
data Term =
|
||||
Vr Ident -- ^ variable
|
||||
| Cn Ident -- ^ constant
|
||||
| Con Ident -- ^ constructor
|
||||
| Sort Ident -- ^ basic type
|
||||
| EInt Integer -- ^ integer literal
|
||||
| EFloat Double -- ^ floating point literal
|
||||
| K String -- ^ string literal or token: @\"foo\"@
|
||||
| Empty -- ^ the empty string @[]@
|
||||
|
||||
| App Term Term -- ^ application: @f a@
|
||||
| Abs BindType Ident Term -- ^ abstraction: @\x -> b@
|
||||
| Meta {-# UNPACK #-} !MetaId -- ^ metavariable: @?i@ (only parsable: ? = ?0)
|
||||
| ImplArg Term -- ^ placeholder for implicit argument @{t}@
|
||||
| Prod BindType Ident Term Term -- ^ function type: @(x : A) -> B@, @A -> B@, @({x} : A) -> B@
|
||||
| Typed Term Term -- ^ type-annotated term
|
||||
--
|
||||
-- /below this, the constructors are only for concrete syntax/
|
||||
| Example Term String -- ^ example-based term: @in M.C "foo"
|
||||
| RecType [Labelling] -- ^ record type: @{ p : A ; ...}@
|
||||
| R [Assign] -- ^ record: @{ p = a ; ...}@
|
||||
| P Term Label -- ^ projection: @r.p@
|
||||
| ExtR Term Term -- ^ extension: @R ** {x : A}@ (both types and terms)
|
||||
|
||||
| Table Term Term -- ^ table type: @P => A@
|
||||
| T TInfo [Case] -- ^ table: @table {p => c ; ...}@
|
||||
| V Type [Term] -- ^ table given as course of values: @table T [c1 ; ... ; cn]@
|
||||
| S Term Term -- ^ selection: @t ! p@
|
||||
|
||||
| Let LocalDef Term -- ^ local definition: @let {t : T = a} in b@
|
||||
|
||||
| Q QIdent -- ^ qualified constant from a package
|
||||
| QC QIdent -- ^ qualified constructor from a package
|
||||
|
||||
| C Term Term -- ^ concatenation: @s ++ t@
|
||||
| Glue Term Term -- ^ agglutination: @s + t@
|
||||
|
||||
| EPatt Int (Maybe Int) Patt -- ^ pattern (in macro definition): # p
|
||||
| EPattType Term -- ^ pattern type: pattern T
|
||||
|
||||
| ELincat Ident Term -- ^ boxed linearization type of Ident
|
||||
| ELin Ident Term -- ^ boxed linearization of type Ident
|
||||
|
||||
| AdHocOverload [Term] -- ^ ad hoc overloading generated in Rename
|
||||
|
||||
| FV [Term] -- ^ alternatives in free variation: @variants { s ; ... }@
|
||||
|
||||
| Alts Term [(Term, Term)] -- ^ alternatives by prefix: @pre {t ; s\/c ; ...}@
|
||||
| Strs [Term] -- ^ conditioning prefix strings: @strs {s ; ...}@
|
||||
| TSymCat Int LIndex [(LIndex,(Ident,Type))]
|
||||
| TSymVar Int Int
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
-- | Patterns
|
||||
data Patt =
|
||||
PC Ident [Patt] -- ^ constructor pattern: @C p1 ... pn@ @C@
|
||||
| PP QIdent [Patt] -- ^ package constructor pattern: @P.C p1 ... pn@ @P.C@
|
||||
| PV Ident -- ^ variable pattern: @x@
|
||||
| PW -- ^ wild card pattern: @_@
|
||||
| PR [(Label,Patt)] -- ^ record pattern: @{r = p ; ...}@ -- only concrete
|
||||
| PString String -- ^ string literal pattern: @\"foo\"@ -- only abstract
|
||||
| PInt Integer -- ^ integer literal pattern: @12@ -- only abstract
|
||||
| PFloat Double -- ^ float literal pattern: @1.2@ -- only abstract
|
||||
| PT Type Patt -- ^ type-annotated pattern
|
||||
|
||||
| PAs Ident Patt -- ^ as-pattern: x@p
|
||||
|
||||
| PImplArg Patt -- ^ placeholder for pattern for implicit argument @{p}@
|
||||
| PTilde Term -- ^ inaccessible pattern
|
||||
|
||||
-- regular expression patterns
|
||||
| PNeg Patt -- ^ negated pattern: -p
|
||||
| PAlt Patt Patt -- ^ disjunctive pattern: p1 | p2
|
||||
| PSeq Int (Maybe Int) Patt Int (Maybe Int) Patt
|
||||
-- ^ sequence of token parts: p + q
|
||||
-- In the constructor PSeq minp maxp p minq maxq q,
|
||||
-- minp/maxp and minq/maxq are the minimal/maximal
|
||||
-- length of a matching string for p/q.
|
||||
| PRep Int (Maybe Int) Patt
|
||||
-- ^ repetition of token part: p*
|
||||
-- In the constructor PRep minp maxp p,
|
||||
-- minp/maxp is the minimal/maximal length of
|
||||
-- a matching string for p.
|
||||
|
||||
| PChar -- ^ string of length one: ?
|
||||
| PChars [Char] -- ^ character list: ["aeiou"]
|
||||
| PMacro Ident -- #p
|
||||
| PM QIdent -- #m.p
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
-- | to guide computation and type checking of tables
|
||||
data TInfo =
|
||||
TRaw -- ^ received from parser; can be anything
|
||||
| TTyped Type -- ^ type annontated, but can be anything
|
||||
| TComp Type -- ^ expanded
|
||||
| TWild Type -- ^ just one wild card pattern, no need to expand
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
-- | record label
|
||||
data Label =
|
||||
LIdent RawIdent
|
||||
| LVar Int
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
type MetaId = Int
|
||||
|
||||
type Hypo = (BindType,Ident,Type) -- (x:A) (_:A) A ({x}:A)
|
||||
type Context = [Hypo] -- (x:A)(y:B) (x,y:A) (_,_:A)
|
||||
type Equation = ([Patt],Term)
|
||||
|
||||
type Labelling = (Label, Type)
|
||||
type Assign = (Label, (Maybe Type, Term))
|
||||
type Case = (Patt, Term)
|
||||
--type Cases = ([Patt], Term)
|
||||
type LocalDef = (Ident, (Maybe Type, Term))
|
||||
|
||||
type Param = (Ident, Context)
|
||||
type Altern = (Term, [(Term, Term)])
|
||||
|
||||
type Substitution = [(Ident, Term)]
|
||||
|
||||
varLabel :: Int -> Label
|
||||
varLabel = LVar
|
||||
|
||||
tupleLabel, linLabel :: Int -> Label
|
||||
tupleLabel i = LIdent $! rawIdentS ('p':show i)
|
||||
linLabel i = LIdent $! rawIdentS ('s':show i)
|
||||
|
||||
theLinLabel :: Label
|
||||
theLinLabel = LIdent (rawIdentS "s")
|
||||
|
||||
ident2label :: Ident -> Label
|
||||
ident2label c = LIdent (ident2raw c)
|
||||
|
||||
label2ident :: Label -> Ident
|
||||
label2ident (LIdent s) = identC s
|
||||
label2ident (LVar i) = identS ('$':show i)
|
||||
Reference in New Issue
Block a user