hssqlppp-0.0.10: Database/HsSqlPpp/AstInternals/AstInternal.ag
{-
Copyright 2009 Jake Wheat
This file contains the ast nodes, and the api functions to pass an ast
and get back type information.
It uses the Utrecht University Attribute Grammar system:
http://www.cs.uu.nl/wiki/bin/view/HUT/AttributeGrammarSystem
http://www.haskell.org/haskellwiki/The_Monad.Reader/Issue4/Why_Attribute_Grammars_Matter
The attr and sem definitions are in TypeChecking.ag, which is included
into this file.
These ast nodes are both used as the result of successful parsing, and
as the input to the type checker (and the output from the type
checker), and the pretty printer.
= compiling
use
uuagc -dcfwsp --cycle --genlinepragmas AstInternal.ag
to generate a new AstInternal.hs from this file (cycle will check for
cycles - it's bad if you get any of these, and genlinepragmas mean
that you'll be able to view the original source ag positions when
there are errors or warnings compiling the generated hs file, which
you want much more often than not).
(install uuagc with
cabal install uuagc
)
-}
MODULE {Database.HsSqlPpp.AstInternals.AstInternal}
{
-- {-# LANGUAGE DeriveDataTypeable,RankNTypes,ScopedTypeVariables #-}
-- {-# OPTIONS_HADDOCK hide #-}
--from the ag files:
--ast nodes
Statement (..)
,SelectExpression (..)
,FnBody (..)
,SetClause (..)
,TableRef (..)
,JoinExpression (..)
,JoinType (..)
,SelectList (..)
,SelectItem (..)
,CopySource (..)
,AttributeDef (..)
,RowConstraint (..)
,Constraint (..)
,TypeAttributeDef (..)
,ParamDef (..)
,VarDef (..)
,RaiseType (..)
,CombineType (..)
,Volatility (..)
,Language (..)
,TypeName (..)
,DropType (..)
,Cascade (..)
,Direction (..)
,Distinct (..)
,Natural (..)
,IfExists (..)
,RestartIdentity (..)
,Expression (..)
,InList (..)
,StatementList
,ExpressionListStatementListPairList
,ExpressionListStatementListPair
,ExpressionList
,StringList
,ParamDefList
,AttributeDefList
,ConstraintList
,TypeAttributeDefList
,StringStringListPairList
,StringStringListPair
,ExpressionStatementListPairList
,SetClauseList
,CaseExpressionListExpressionPairList
,MaybeExpression
,TableRefList
,ExpressionListList
,SelectItemList
,OnExpr
,RowConstraintList
,VarDefList
,ExpressionStatementListPair
,CaseExpressionListExpressionPair
,CaseExpressionList
,ExpressionDirectionPair
,ExpressionDirectionPairList
,MaybeBoolExpression
-- annotations
,annotateAst
,annotateAstEnv
,annotateExpression
,annotateAstsEnv
,annotateAstEnvEnv
}
{
import Data.Maybe
import Data.List
import Debug.Trace
import Control.Monad.Error
import Control.Arrow
import Data.Either
import Control.Applicative
import Data.Generics
import Database.HsSqlPpp.AstInternals.TypeType
import Database.HsSqlPpp.AstInternals.TypeConversion
import Database.HsSqlPpp.AstInternals.TypeCheckingH
import Database.HsSqlPpp.AstInternals.AstAnnotation
import Database.HsSqlPpp.AstInternals.EnvironmentInternal
import Database.HsSqlPpp.AstInternals.DefaultTemplate1Environment
import Database.HsSqlPpp.Utils
}
{-
================================================================================
SQL top level statements
everything is chucked in here: dml, ddl, plpgsql statements
-}
DATA Statement
--queries
| SelectStatement ann:Annotation ex:SelectExpression
-- dml
--table targetcolumns insertdata(values or select statement) returning
| Insert ann:Annotation
table : String
targetCols : StringList
insData : SelectExpression
returning : (Maybe SelectList)
--tablename setitems where returning
| Update ann:Annotation
table : String
assigns : SetClauseList
whr : MaybeBoolExpression
returning : (Maybe SelectList)
--tablename, where, returning
| Delete ann:Annotation
table : String
whr : MaybeBoolExpression
returning : (Maybe SelectList)
--tablename column names, from
| Copy ann:Annotation
table : String
targetCols : StringList
source : CopySource
--represents inline data for copy statement
| CopyData ann:Annotation insData : String
| Truncate ann:Annotation
tables: StringList
restartIdentity : RestartIdentity
cascade : Cascade
-- ddl
| CreateTable ann:Annotation
name : String
atts : AttributeDefList
cons : ConstraintList
| CreateTableAs ann:Annotation
name : String
expr : SelectExpression
| CreateView ann:Annotation
name : String
expr : SelectExpression
| CreateType ann:Annotation
name : String
atts : TypeAttributeDefList
-- language name args rettype bodyquoteused body vol
| CreateFunction ann:Annotation
lang : Language
name : String
params : ParamDefList
rettype : TypeName
bodyQuote : String
body : FnBody
vol : Volatility
-- name type checkexpression
| CreateDomain ann:Annotation
name : String
typ : TypeName
check : MaybeBoolExpression
-- ifexists (name,argtypes)* cascadeorrestrict
| DropFunction ann:Annotation
ifE : IfExists
sigs : StringStringListPairList
cascade : Cascade
-- ifexists names cascadeorrestrict
| DropSomething ann:Annotation
dropType : DropType
ifE : IfExists
names : StringList
cascade : Cascade
| Assignment ann:Annotation
target : String
value : Expression
| Return ann:Annotation
value : (MaybeExpression)
| ReturnNext ann:Annotation
expr : Expression
| ReturnQuery ann:Annotation
sel : SelectExpression
| Raise ann:Annotation
level : RaiseType
message : String
args : ExpressionList
| NullStatement ann:Annotation
| Perform ann:Annotation
expr : Expression
| Execute ann:Annotation
expr : Expression
| ExecuteInto ann:Annotation
expr : Expression
targets : StringList
| ForSelectStatement ann:Annotation
var : String
sel : SelectExpression
sts : StatementList
| ForIntegerStatement ann:Annotation
var : String
from : Expression
to : Expression
sts : StatementList
| WhileStatement ann:Annotation
expr : Expression
sts : StatementList
| ContinueStatement ann:Annotation
--variable, list of when parts, else part
| CaseStatement ann:Annotation
val : Expression
cases : ExpressionListStatementListPairList
els : StatementList
--list is
--first if (condition, statements):elseifs(condition, statements)
--last bit is else statements
| If ann:Annotation
cases : ExpressionStatementListPairList
els : StatementList
-- =============================================================================
--Statement components
-- maybe this should be called relation valued expression?
DATA SelectExpression
| Select ann:Annotation
selDistinct : Distinct
selSelectList : SelectList
selTref : TableRefList
selWhere : MaybeBoolExpression
selGroupBy : ExpressionList
selHaving : MaybeBoolExpression
selOrderBy : ExpressionDirectionPairList
selLimit : MaybeExpression
selOffset : MaybeExpression
| CombineSelect ann:Annotation
ctype : CombineType
sel1 : SelectExpression
sel2 : SelectExpression
| Values ann:Annotation
vll:ExpressionListList
TYPE TableRefList = [TableRef]
TYPE MaybeExpression = MAYBE Expression
TYPE MaybeBoolExpression = MAYBE Expression
DATA FnBody | SqlFnBody ann:Annotation sts : StatementList
| PlpgsqlFnBody ann:Annotation vars:VarDefList sts : StatementList
DATA SetClause | SetClause ann:Annotation att:String val:Expression
| RowSetClause ann:Annotation atts:StringList vals:ExpressionList
DATA TableRef | Tref ann:Annotation
tbl:String
| TrefAlias ann:Annotation
tbl : String
alias : String
| JoinedTref ann:Annotation
tbl : TableRef
nat : Natural
joinType : JoinType
tbl1 : TableRef
onExpr : OnExpr
| SubTref ann:Annotation
sel : SelectExpression
alias : String
| TrefFun ann:Annotation
fn:Expression
| TrefFunAlias ann:Annotation
fn:Expression
alias:String
TYPE OnExpr = MAYBE JoinExpression
DATA JoinExpression | JoinOn ann:Annotation Expression
| JoinUsing ann:Annotation StringList
DATA JoinType | Inner | LeftOuter| RightOuter | FullOuter | Cross
-- select columns, into columns
DATA SelectList | SelectList ann:Annotation items:SelectItemList StringList
DATA SelectItem | SelExp ann:Annotation ex:Expression
| SelectItem ann:Annotation ex:Expression name:String
DATA CopySource | CopyFilename String
| Stdin
--name type default null constraint
DATA AttributeDef | AttributeDef ann:Annotation
name : String
typ : TypeName
def: MaybeExpression
cons : RowConstraintList
--Constraints which appear attached to an individual field
DATA RowConstraint | NullConstraint ann:Annotation
| NotNullConstraint ann:Annotation
| RowCheckConstraint ann:Annotation Expression
| RowUniqueConstraint ann:Annotation
| RowPrimaryKeyConstraint ann:Annotation
| RowReferenceConstraint ann:Annotation
table : String
att : (Maybe String)
onUpdate : Cascade
onDelete : Cascade
--constraints which appear on a separate row in the create table
DATA Constraint | UniqueConstraint ann:Annotation StringList
| PrimaryKeyConstraint ann:Annotation StringList
| CheckConstraint ann:Annotation Expression
-- sourcecols targettable targetcols ondelete onupdate
| ReferenceConstraint ann:Annotation
atts : StringList
table : String
tableAtts : StringList
onUpdate : Cascade
onDelete : Cascade
DATA TypeAttributeDef | TypeAttDef ann:Annotation
name : String
typ : TypeName
DATA ParamDef | ParamDef ann:Annotation name:String typ:TypeName
| ParamDefTp ann:Annotation typ:TypeName
DATA VarDef | VarDef ann:Annotation
name : String
typ : TypeName
value : (Maybe Expression)
DATA RaiseType | RNotice | RException | RError
DATA CombineType | Except | Union | Intersect | UnionAll
DATA Volatility | Volatile | Stable | Immutable
DATA Language | Sql | Plpgsql
DATA TypeName | SimpleTypeName ann:Annotation tn:String
| PrecTypeName ann:Annotation tn:String prec:Integer
| ArrayTypeName ann:Annotation typ:TypeName
| SetOfTypeName ann:Annotation typ:TypeName
DATA DropType | Table
| Domain
| View
| Type
DATA Cascade | Cascade | Restrict
DATA Direction | Asc | Desc
DATA Distinct | Distinct | Dupes
DATA Natural | Natural | Unnatural
DATA IfExists | Require | IfExists
DATA RestartIdentity | RestartIdentity | ContinueIdentity
{-
================================================================================
Expressions
Similarly to the statement type, all expressions are chucked into one
even though there are many restrictions on which expressions can
appear in different places. Maybe this should be called scalar
expression?
-}
DATA Expression | IntegerLit ann:Annotation i:Integer
| FloatLit ann:Annotation d:Double
| StringLit ann:Annotation
quote : String
value : String
| NullLit ann:Annotation
| BooleanLit ann:Annotation b:Bool
| PositionalArg ann:Annotation p:Integer
| Cast ann:Annotation
expr:Expression
tn:TypeName
| Identifier ann:Annotation
i:String
| Case ann:Annotation
cases : CaseExpressionListExpressionPairList
els : MaybeExpression
| CaseSimple ann:Annotation
value : Expression
cases : CaseExpressionListExpressionPairList
els : MaybeExpression
| Exists ann:Annotation
sel : SelectExpression
| FunCall ann:Annotation
funName:String
args:ExpressionList
| InPredicate ann:Annotation
expr:Expression
i:Bool
list:InList
-- windowfn selectitem partitionby orderby orderbyasc?
| WindowFn ann:Annotation
fn : Expression
partitionBy : ExpressionList
orderBy : ExpressionList
dir : Direction
| ScalarSubQuery ann:Annotation
sel : SelectExpression
DATA InList | InList ann:Annotation exprs : ExpressionList
| InSelect ann:Annotation sel : SelectExpression
{-
list of expression flavours from postgresql with the equivalents in this ast
pg here
-- ----
constant/literal integerlit, floatlit, unknownstringlit, nulllit, boollit
column reference identifier
positional parameter reference positionalarg
subscripted expression funcall
field selection expression identifier
operator invocation funcall
function call funcall
aggregate expression funcall
window function call windowfn
type cast cast
scalar subquery scalarsubquery
array constructor funcall
row constructor funall
Anything that is represented in the ast as some sort of name plus a
list of expressions as arguments is treated as the same type of node:
FunCall.
This includes
symbol operators
regular function calls
keyword operators e.g. and, like (ones which can be parsed as normal
syntactic operators)
unusual syntax operators, e.g. between
unusual syntax function calls e.g. substring(x from 5 for 3)
arrayctors e.g. array[3,5,6]
rowctors e.g. ROW (2,4,6)
array subscripting
list of keyword operators (regular prefix, infix and postfix):
and, or, not
is null, is not null, isnull, notnull
is distinct from, is not distinct from
is true, is not true,is false, is not false, is unknown, is not unknown
like, not like, ilike, not ilike
similar to, not similar to
in, not in (don't include these here since the argument isn't always an expr)
unusual syntax operators and fn calls
between, not between, between symmetric
overlay, substring, trim
any, some, all
Most of unusual syntax forms and keywords operators are not yet
supported, so this is mainly a todo list.
Keyword operators are encoded with the function name as a ! followed
by a string
e.g.
operator 'and' -> FunCall "!and" ...
see keywordOperatorTypes value in AstUtils.lhs for the list of
currently supported keyword operators.
-}
-- some list nodes, not sure if all of these are needed as separately
-- named node types
TYPE ExpressionList = [Expression]
TYPE ExpressionListList = [ExpressionList]
TYPE StringList = [String]
TYPE SetClauseList = [SetClause]
TYPE AttributeDefList = [AttributeDef]
TYPE ConstraintList = [Constraint]
TYPE TypeAttributeDefList = [TypeAttributeDef]
TYPE ParamDefList = [ParamDef]
TYPE StringStringListPair = (String,StringList)
TYPE StringStringListPairList = [StringStringListPair]
TYPE ExpressionListStatementListPair = (ExpressionList,StatementList)
TYPE ExpressionListStatementListPairList = [ExpressionListStatementListPair]
TYPE ExpressionStatementListPair = (Expression, StatementList)
TYPE ExpressionStatementListPairList = [ExpressionStatementListPair]
TYPE VarDefList = [VarDef]
TYPE SelectItemList = [SelectItem]
TYPE RowConstraintList = [RowConstraint]
TYPE CaseExpressionListExpressionPair = (CaseExpressionList,Expression)
TYPE CaseExpressionList = [Expression]
TYPE CaseExpressionListExpressionPairList = [CaseExpressionListExpressionPair]
TYPE StatementList = [Statement]
TYPE ExpressionDirectionPair = (Expression,Direction)
TYPE ExpressionDirectionPairList = [ExpressionDirectionPair]
-- Add a root data type so we can put initial values for inherited
-- attributes in the section which defines and uses those attributes
-- rather than in the sem_ calls
DATA Root | Root statements:StatementList
DERIVING Root: Show
-- use an expression root also to support type checking,
-- etc., individual expressions
DATA ExpressionRoot | ExpressionRoot expr:Expression
DERIVING ExpressionRoot: Show
{-
================================================================================
=some basic bookkeeping
attributes which every node has
-}
SET AllNodes = Statement SelectExpression FnBody SetClause TableRef
JoinExpression JoinType
SelectList SelectItem CopySource AttributeDef RowConstraint
Constraint TypeAttributeDef ParamDef VarDef RaiseType
CombineType Volatility Language TypeName DropType Cascade
Direction Distinct Natural IfExists RestartIdentity
Expression InList MaybeExpression MaybeBoolExpression
ExpressionList ExpressionListList StringList SetClauseList
AttributeDefList ConstraintList TypeAttributeDefList
ParamDefList StringStringListPair StringStringListPairList
StatementList ExpressionListStatementListPair
ExpressionListStatementListPairList ExpressionStatementListPair
ExpressionStatementListPairList VarDefList SelectItemList
RowConstraintList CaseExpressionListExpressionPair
CaseExpressionListExpressionPairList CaseExpressionList
TableRefList TableRef OnExpr ExpressionDirectionPair
ExpressionDirectionPairList
DERIVING AllNodes: Show,Eq,Typeable,Data
INCLUDE "TypeChecking.ag"
{-
================================================================================
used to use record syntax to try to insulate code from field changes,
and not have to write out loads of nothings and [] for simple selects,
but don't know how to create haskell named records from uuagc DATA
things
makeSelect :: Statement
makeSelect = Select Dupes (SelectList [SelExp (Identifier "*")] [])
Nothing Nothing [] Nothing [] Asc Nothing Nothing
================================================================================
= annotation functions
-}
{
-- | Takes an ast, and adds annotations, including types, type errors,
-- and statement info. Type checks against defaultEnv.
annotateAst :: StatementList -> StatementList
annotateAst = annotateAstEnv defaultTemplate1Environment
-- | As annotateAst but you supply an environment to check
-- against. See Environment module for how to read an Environment from
-- an existing database so you can type check against it.
annotateAstEnv :: Environment -> StatementList -> StatementList
annotateAstEnv env sts =
let t = sem_Root (Root sts)
ta = wrap_Root t Inh_Root {env_Inh_Root = env}
tl = annotatedTree_Syn_Root ta
in case tl of
Root r -> r
-- | Type check multiple asts, allowing type checking references in later
-- files to definitions in earlier files.
annotateAstsEnv :: Environment -> [StatementList] -> [StatementList]
annotateAstsEnv env sts =
annInt env sts []
where
annInt e (s:ss) ress =
let (e1,res) = annotateAstEnvEnv e s
in annInt e1 ss (res:ress)
annInt _ [] ress = reverse ress
-- | Type check an ast, and return the resultant Environment as well
-- as the annotated ast.
annotateAstEnvEnv :: Environment -> StatementList -> (Environment,StatementList)
annotateAstEnvEnv env sts =
let t = sem_Root (Root sts)
ta = wrap_Root t Inh_Root {env_Inh_Root = env}
tl = annotatedTree_Syn_Root ta
env1 = producedEnv_Syn_Root ta
in case tl of
Root r -> (env1,r)
-- | Testing utility, mainly used to check an expression for type errors
-- or to get its type.
annotateExpression :: Environment -> Expression -> Expression
annotateExpression env ex =
let t = sem_ExpressionRoot (ExpressionRoot ex)
rt = (annotatedTree_Syn_ExpressionRoot
(wrap_ExpressionRoot t Inh_ExpressionRoot {env_Inh_ExpressionRoot = env}))
in case rt of
ExpressionRoot e -> e
}
{-
Future plans:
Investigate how much mileage can get out of making these nodes the
parse tree nodes, and using a separate ast. Hinges on how much extra
value can get from making the types more restrictive for the ast nodes
compared to the parse tree. Starting to think this won't be worth it.
Would like to turn this back into regular Haskell file, maybe could
use AspectAG instead of uuagc to make this happen?
-}