INCLUDE "HsToken.ag" imports { import qualified Data.Sequence as Seq import Data.Sequence(Seq,empty,singleton,(><)) import Data.Foldable(toList) import Pretty import TokenDef import HsToken import ErrorMessages } ATTR HsTokensRoot [ | | errors USE {Seq.><} {Seq.empty}:{Seq Error} usedLocals:{[Identifier]} usedAttrs :{[(Identifier,Identifier)]} textLines :{[String]} usedFields:{[Identifier]} ] ------------------------------------------------------------------------------- -- Context information ------------------------------------------------------------------------------- ATTR HsTokensRoot HsTokens HsToken [ nt,con : {Identifier} allfields : {[(Identifier,Type,ChildKind)]} allnts : {[Identifier]} attrs : {[(Identifier,Identifier)]} options : {Options} || ] ATTR HsTokens HsToken [ fieldnames : {[Identifier]} | | ] SEM HsTokensRoot | HsTokensRoot tokens.fieldnames = map (\(n,_,_) -> n) @lhs.allfields ------------------------------------------------------------------------------- -- Errors ------------------------------------------------------------------------------- ATTR HsTokens HsToken [ | | errors USE {Seq.><} {Seq.empty}:{Seq Error} ] ------------------------------------------------------------------------------- -- Syntax errors ------------------------------------------------------------------------------- SEM HsToken | Err lhs.errors = let m = text @mesg in Seq.singleton (CustomError False @pos m) ------------------------------------------------------------------------------- -- Undefined variables ------------------------------------------------------------------------------- { isNTname allnts (Just (NT nt _ _)) = nt `elem` allnts isNTname allnts _ = False } -- An AGLocal is either a local variable or a terminal SEM HsToken | AGLocal loc.tkAsLocal = AGLocal @var @pos @rdesc -- refers to the terminal loc.tkAsField = AGField _LOC @var @pos @rdesc -- refers to the (local) attribute loc.(errors,output,tok,usedLocals) = if @var `elem` @lhs.fieldnames -- check if @var occurs as a terminal then if isNTname @lhs.allnts (lookup @var (map (\(n,t,_) -> (n,t)) @lhs.allfields)) then (Seq.singleton(ChildAsLocal @lhs.nt @lhs.con @var), @loc.tkAsLocal,(@pos,fieldname @var), [] ) else (Seq.empty, @loc.tkAsLocal, (@pos,fieldname @var), [] ) else if (_LOC,@var) `elem` @lhs.attrs then (Seq.empty , @loc.tkAsField, (@pos,locname @lhs.options @var), [@var]) else (Seq.singleton(UndefLocal @lhs.nt @lhs.con @var), @loc.tkAsField, (@pos,locname @lhs.options @var), [] ) SEM HsToken | AGField lhs.errors = if (@field,@attr) `elem` @lhs.attrs then Seq.empty else if not(@field `elem` (_LHS : _LOC: @lhs.fieldnames)) then Seq.singleton (UndefChild @lhs.nt @lhs.con @field) else Seq.singleton (UndefAttr @lhs.nt @lhs.con @field @attr False) ------------------------------------------------------------------------------- -- Used variables ------------------------------------------------------------------------------- ATTR HsTokens HsToken [ | | usedLocals USE {++} {[]} : {[Identifier]} usedAttrs USE {++} {[]} : {[(Identifier,Identifier)]} ] SEM HsToken | AGField (lhs.usedAttrs,lhs.usedLocals) = if @field == _LOC then ([], [@attr]) else ([(@field,@attr)], []) ------------------------------------------------------------------------------- -- Used fields ------------------------------------------------------------------------------- ATTR HsTokens HsToken [ | | usedFields USE {Seq.><} {Seq.empty} : {Seq Identifier} ] SEM HsToken | AGLocal lhs.usedFields = if @var `elem` @lhs.fieldnames then Seq.singleton @var else Seq.empty SEM HsTokensRoot | HsTokensRoot lhs.usedFields = toList @tokens.usedFields ------------------------------------------------------------------------------- -- Pretty printing ------------------------------------------------------------------------------- SEM HsTokensRoot | HsTokensRoot lhs.textLines = showTokens @tokens.tks SEM HsTokens [ || tks : {[(Pos,String)]} ] | Cons lhs.tks = @hd.tok : @tl.tks | Nil lhs.tks = [] SEM HsToken [ || tok:{(Pos,String)}] | AGField loc.addTrace = case @rdesc of Just d -> \x -> "(trace " ++ show (d ++ " -> " ++ show @field ++ "." ++ show @attr) ++ " (" ++ x ++ "))" Nothing -> id lhs.tok = (@pos, @loc.addTrace $ attrname @lhs.options True @field @attr) | HsToken lhs.tok = (@pos, @value) | CharToken lhs.tok = (@pos, if null @value then "" else showCharShort (head @value) ) | StrToken lhs.tok = (@pos, showStrShort @value) | Err lhs.tok = (@pos, "") ------------------------------------------------------------------------------- -- Desugar (resolve AGLocals to explicit AGFields) ------------------------------------------------------------------------------- ATTR HsTokensRoot [ | | output : {[HsToken]} ] ATTR HsTokens HsToken [ | | output : SELF ]