1 {-# LANGUAGE DeriveLift #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE NoMonomorphismRestriction #-}
4 {-# LANGUAGE Rank2Types #-}
5 {-# LANGUAGE ScopedTypeVariables #-}
6 {-# LANGUAGE StandaloneDeriving #-}
7 {-# LANGUAGE TemplateHaskell #-}
8 {-# LANGUAGE UnboxedTuples #-}
9 module Grammar.Nandlang where
12 import Data.Char (isSpace, isAlpha, isAlphaNum)
13 import Data.Char (Char)
14 import Data.Eq (Eq(..))
15 import Data.Ord (Ord(..))
16 import Data.String (String)
17 import qualified Data.Set as Set
18 import qualified Data.Text as Text
20 import Symantic.Univariant.Trans
21 import qualified Symantic.Parser as P
22 import qualified Symantic.Parser.Haskell as H
24 type Parser a = P.Parser Text.Text a
26 nandIdentStart :: Char -> Bool
27 nandIdentStart c = isAlpha c || c == '_'
29 nandIdentLetter :: Char -> Bool
30 nandIdentLetter c = isAlphaNum c || c == '_'
32 nandUnreservedName :: String -> Bool
33 nandUnreservedName = \s -> not (Set.member s keys)
35 keys = Set.fromList ["if", "else", "while", "function", "var"]
37 nandStringLetter :: Char -> Bool
38 nandStringLetter c = (c /= '"') && (c /= '\\') && (c > '\026')
40 grammar :: forall repr.
41 P.Grammar Char repr =>
43 grammar = whitespace P.*> P.skipMany funcdef P.<* P.eof
48 identifier = P.try (identStart P.*> P.skipMany identLetter) P.*> whitespace
50 variable = identifier P.*> P.optional index
53 literal = bit P.<|> charLit
55 keyword :: String -> repr ()
56 keyword s = P.try (P.string s P.*> notIdentLetter) P.*> whitespace
58 identStart = P.satisfy
59 [P.ErrorItemLabel "identStart"]
60 (trans (H.ValueCode nandIdentStart [||nandIdentStart||]))
61 identLetter = P.satisfy
62 [P.ErrorItemLabel "identLetter"]
63 (trans (H.ValueCode nandIdentLetter [||nandIdentLetter||]))
64 notIdentLetter = P.negLook identLetter
67 bit = (P.char '0' P.<|> P.char '1') P.*> whitespace
73 charLit = P.between (P.char '\'') (symbol '\'') charChar
76 charChar = P.void (P.satisfy
77 [P.ErrorItemLabel "Char"]
78 (trans (H.ValueCode nandStringLetter [||nandStringLetter||]))) P.<|> esc
81 esc = P.char '\\' P.*> P.void (P.oneOf "0tnvfr")
84 expr = nandexpr P.*> P.skipMany (symbol '!' P.*> nandexpr)
87 nandexpr = literal P.<|> funccallOrVar
89 funccallOrVar :: repr ()
90 funccallOrVar = identifier P.*> P.optional (parens exprlist P.<|> index)
92 exprlist = commaSep expr
93 exprlist1 = commaSep1 expr
94 varlist = commaSep variable
95 varlist1 = commaSep1 variable
97 funcparam = varlist P.*> P.optional (symbol ':' P.*> varlist)
98 varstmt = P.optional (keyword "var") P.*> varlist1 P.*> symbol '=' P.*> exprlist1 P.<* semi
99 ifstmt = keyword "if" P.*> expr P.*> block P.*> P.optional (keyword "else" P.*> block)
100 whilestmt = keyword "while" P.*> expr P.*> block
101 statement = ifstmt P.<|> whilestmt P.<|> P.try varstmt P.<|> expr P.<* semi
102 block = braces (P.skipMany statement)
103 funcdef = keyword "function" P.*> identifier P.*> parens funcparam P.*> block
106 decimal = number (P.oneOf ['0'..'9'])
107 -- hexadecimal = P.oneOf "xX" P.*> number (P.oneOf (['a'..'f'] <> ['A'..'F'] <> ['0'..'9']))
108 -- octal = P.oneOf "oO" P.*> number (P.oneOf ['0'..'7'])
109 number :: repr a -> repr ()
110 number digit = P.skipSome digit
112 symbol :: Char -> repr Char
113 symbol c = P.char c P.<* whitespace
114 parens :: repr a -> repr a
115 parens = P.between (symbol '(') (symbol ')')
116 brackets :: repr a -> repr a
117 brackets = P.between (symbol '[') (symbol ']')
118 braces :: repr a -> repr a
119 braces = P.between (symbol '{') (symbol '}')
124 commaSep :: repr a -> repr ()
125 commaSep p = P.optional (commaSep1 p)
126 commaSep1 :: repr a -> repr ()
127 commaSep1 p = p P.*> P.skipMany (comma P.*> p)
130 space = P.void (P.satisfy
131 [P.ErrorItemLabel "space"]
132 (trans (H.ValueCode isSpace [||isSpace||])))
133 whitespace :: repr ()
134 whitespace = P.skipMany (spaces P.<|> oneLineComment)
136 spaces = P.skipSome space
137 oneLineComment :: repr ()
138 oneLineComment = P.void (P.string "//" P.*> P.skipMany (P.satisfy
139 [P.ErrorItemLabel "oneLineComment"]
140 (trans (H.ValueCode (/= '\n') [||(/= '\n')||]))))