246 lines
6.9 KiB
Plaintext
246 lines
6.9 KiB
Plaintext
{
|
|
{-# OPTIONS_GHC -w #-}
|
|
|
|
-- vim: filetype=haskell
|
|
|
|
module Syntax.Parser where
|
|
|
|
import Syntax.AST
|
|
import Syntax.Lexer
|
|
import Syntax.ParserCore
|
|
|
|
import MonadLib
|
|
import qualified Codec.Binary.UTF8.Generic as UTF8
|
|
|
|
}
|
|
|
|
%token
|
|
|
|
-- reserved words
|
|
'module' { Lexeme $$ (TokValIdent "module" ) }
|
|
'export' { Lexeme $$ (TokValIdent "export" ) }
|
|
'import' { Lexeme $$ (TokValIdent "import" ) }
|
|
'data' { Lexeme $$ (TokValIdent "data" ) }
|
|
'type' { Lexeme $$ (TokValIdent "type" ) }
|
|
'newtype' { Lexeme $$ (TokValIdent "newtype" ) }
|
|
'class' { Lexeme $$ (TokValIdent "class" ) }
|
|
'instance' { Lexeme $$ (TokValIdent "instance") }
|
|
'qualified' { Lexeme $$ (TokValIdent "instance") }
|
|
'as' { Lexeme $$ (TokValIdent "instance") }
|
|
|
|
-- symbols
|
|
'=' { Lexeme $$ (TokOpIdent "=") }
|
|
'->' { Lexeme $$ (TokOpIdent "->") }
|
|
'=>' { Lexeme $$ (TokOpIdent "=>") }
|
|
'\\' { Lexeme $$ (TokOpIdent "\\") }
|
|
'(' { Lexeme $$ LParen }
|
|
')' { Lexeme $$ RParen }
|
|
'[' { Lexeme $$ LSquare }
|
|
']' { Lexeme $$ RSquare }
|
|
'{' { Lexeme $$ LBrace }
|
|
'}' { Lexeme $$ RBrace }
|
|
'|' { Lexeme $$ Bar }
|
|
';' { Lexeme $$ Semi }
|
|
',' { Lexeme $$ Comma }
|
|
|
|
-- identifiers
|
|
TYPE_IDENT { Lexeme _ (TokTypeIdent $$) }
|
|
VAL_IDENT { Lexeme _ (TokValIdent $$) }
|
|
OP_IDENT { Lexeme _ (TokOpIdent $$) }
|
|
|
|
-- values
|
|
INTVAL { Lexeme _ (TokInt $$) }
|
|
FLOATVAL { Lexeme _ (TokFloat $$) }
|
|
CHARVAL { Lexeme _ (TokChar $$) }
|
|
STRVAL { Lexeme _ (TokString $$) }
|
|
|
|
%monad { Parser } { (>>=) } { return }
|
|
%name parseModule top_module
|
|
%tokentype { Lexeme }
|
|
|
|
%lexer { lexer } { Lexeme initPosition TokEOF }
|
|
|
|
%%
|
|
|
|
top_module :: { Module () } : 'module' TYPE_IDENT module_decls {
|
|
let (imports,items) = $3
|
|
in Module (makeQualified $2) imports items
|
|
}
|
|
|
|
module_decls :: { ([Import], [Decl ()]) }
|
|
: module_decls module_decl { $1 `pappend` $2 }
|
|
| module_decl { $1 }
|
|
|
|
module_decl :: { ([Import], [Decl ()]) }
|
|
: data_decl { ([], [$1]) }
|
|
| type_decl { ([], [$1]) }
|
|
| newtype_decl { ([], [$1]) }
|
|
| class_decl { ([], [$1]) }
|
|
| instance_decl { ([], [$1]) }
|
|
| value_decl { ([], [$1]) }
|
|
| import_decl { ([$1], [] ) }
|
|
|
|
-- Data Declarations --------------------------------------------------------
|
|
|
|
data_decl :: { Decl () }
|
|
: 'data' mqualifiers TYPE_IDENT data_args dataclauses
|
|
{ DeclData $2 (makeQualified $3) $4 $5 }
|
|
|
|
mqualifiers :: { [Type] }
|
|
: { [] }
|
|
| '(' tqualifiers ')' '=>' { $2 }
|
|
|
|
tqualifiers :: { [Type] }
|
|
: tqualifier { [$1] }
|
|
| tqualifiers ',' tqualifier { $1 ++ [$3] }
|
|
|
|
tqualifier :: { Type }
|
|
: TYPE_IDENT VAL_IDENT
|
|
{ TAp (TCon (makeQualified $1) Star) (TVar (makeQualified $2) Star) }
|
|
| tqualifier VAL_IDENT
|
|
{ TAp $1 (TVar (makeQualified $2) Star) }
|
|
|
|
data_args :: { [QualifiedName] }
|
|
: { [] }
|
|
| data_args VAL_IDENT { $1 ++ [makeQualified $2] }
|
|
|
|
dataclauses :: { [DataClause] }
|
|
: '=' dataclause { [$2] }
|
|
| dataclauses '|' dataclause { $1 ++ [$3] }
|
|
|
|
dataclause :: { DataClause }
|
|
: TYPE_IDENT { DataClause (makeQualified $1) [] }
|
|
| dataclause bangtype { let DataClause name items = $1
|
|
in DataClause name (items ++ [$2]) }
|
|
|
|
-- Type alias Declarations --------------------------------------------------
|
|
|
|
type_decl :: { Decl () }
|
|
: 'type' { DeclType }
|
|
|
|
newtype_decl :: { Decl () }
|
|
: 'newtype' { DeclNewtype }
|
|
|
|
class_decl :: { Decl () }
|
|
: 'class' { DeclClass }
|
|
|
|
instance_decl :: { Decl () }
|
|
: 'instance' { DeclInstance }
|
|
|
|
value_decl :: { Decl () }
|
|
: VAL_IDENT '=' expr { DeclValue undefined (makeQualified $1) $3 }
|
|
|
|
import_decl :: { Import }
|
|
: 'import' mqualified TYPE_IDENT mimport_list mas
|
|
{ Import (makeQualified $3) $2 $4 $5 }
|
|
|
|
mqualified :: { Bool }
|
|
: { False }
|
|
| 'qualified' { True }
|
|
|
|
mimport_list :: { Maybe [ImportName] }
|
|
: { Nothing }
|
|
| '(' ')' { Just [] }
|
|
| '(' import_list ')' { Just $2 }
|
|
|
|
mas :: { Maybe QualifiedName }
|
|
: { Nothing }
|
|
| 'as' TYPE_IDENT { Just (makeQualified $2) }
|
|
|
|
import_list :: { [ImportName] }
|
|
: import_name { [$1] }
|
|
| import_list ',' import_name { $1 ++ [$3] }
|
|
|
|
import_name :: { ImportName }
|
|
: either_ident { ImportNamed $1 }
|
|
| either_ident 'as' either_ident { ImportRenamed $1 $3 }
|
|
|
|
either_ident :: { QualifiedName }
|
|
: TYPE_IDENT { makeQualified $1 }
|
|
| VAL_IDENT { makeQualified $1 }
|
|
|
|
-- Types --------------------------------------------------------------------
|
|
|
|
bangtype :: { Type }
|
|
: bangtype1 { $1 }
|
|
|
|
bangtype1 :: { Type }
|
|
: bangtype1 VAL_IDENT { TAp $1 (TVar (makeQualified $2) Star) }
|
|
| bangtype2 { $1 }
|
|
|
|
bangtype2 :: { Type }
|
|
: bangtype2 '->' bangtype3
|
|
{ TAp (TAp (TCon (QualifiedName [] "->") Star) $1) $3 }
|
|
| bangtype3 { $1 }
|
|
|
|
bangtype3 :: { Type }
|
|
: TYPE_IDENT { TVar (makeQualified $1) Star }
|
|
| VAL_IDENT { TVar (makeQualified $1) Star }
|
|
| '(' bangtype ')' { $2 }
|
|
|
|
-- Expressions --------------------------------------------------------------
|
|
|
|
expr :: { Expr () }
|
|
: '\\' arglist '->' expr1 { Lambda () $2 $4 }
|
|
| expr1 { $1 }
|
|
|
|
arglist :: { [QualifiedName] }
|
|
: VAL_IDENT { [makeQualified $1] }
|
|
| arglist VAL_IDENT { $1 ++ [makeQualified $2] }
|
|
|
|
expr1 :: { Expr () }
|
|
: '{' exprs '}' { Block () $2 }
|
|
| expr2 { $1 }
|
|
|
|
exprs :: { [Expr ()] }
|
|
: expr ';' { [$1] }
|
|
| exprs expr ';' { $1 ++ [$2] }
|
|
|
|
expr2 :: { Expr () }
|
|
: '[' list_exprs ']' { unwindList $2 }
|
|
| expr3 { $1 }
|
|
|
|
list_exprs :: { [Expr ()] }
|
|
: { [] }
|
|
| list_exprs ',' expr3 { $1 ++ [$3] }
|
|
|
|
expr3 :: { Expr () }
|
|
: bottom_expr { $1 }
|
|
|
|
bottom_expr :: { Expr () }
|
|
: INTVAL { let (b,v) = $1 in Const () (ConstInteger b v) }
|
|
| FLOATVAL { Const () (ConstFloat $1) }
|
|
| CHARVAL { Const () (ConstChar $1) }
|
|
| STRVAL { Const () (ConstString $1) }
|
|
| VAL_IDENT { VarRef () (makeQualified $1) }
|
|
| '(' expr ')' { $2 }
|
|
|
|
{
|
|
lexer :: (Lexeme -> Parser a) -> Parser a
|
|
lexer k = scan >>= k
|
|
|
|
happyError :: Parser a
|
|
happyError = raiseP "Parse Error"
|
|
|
|
pappend :: ([a],[b]) -> ([a],[b]) -> ([a],[b])
|
|
pappend (a,b) (c,d) = (a++c,b++d)
|
|
|
|
unwindList :: [Expr ()] -> Expr ()
|
|
unwindList [] = Const () ConstEmpty
|
|
unwindList (a:rest) =
|
|
App () (App () (VarRef () (QualifiedName ["Data","List"] ":")) a)
|
|
(unwindList rest)
|
|
|
|
makeQualified :: String -> QualifiedName
|
|
makeQualified str = QualifiedName prefixes name
|
|
where
|
|
(prefixes,name) = loop str
|
|
loop val =
|
|
let (pre,rest) = span (/= '.') val
|
|
in if rest == ""
|
|
then ([], pre)
|
|
else let (pres, name) = loop rest
|
|
in (pre:pres, name)
|
|
}
|
|
|