1 {-# LANGUAGE DeriveLift #-}
2 {-# LANGUAGE NoMonomorphismRestriction #-}
3 {-# LANGUAGE Rank2Types #-}
4 {-# LANGUAGE StandaloneDeriving #-}
5 {-# LANGUAGE TemplateHaskell #-}
6 {-# LANGUAGE UnboxedTuples #-}
7 module Parser.Nandlang where
10 import Data.Char (isSpace, isAlpha, isAlphaNum)
11 import Data.Char (Char)
12 import Data.Eq (Eq(..))
13 import Data.Ord (Ord(..))
14 import Data.String (String)
15 import qualified Data.Set as Set
16 import qualified Data.Text as Text
18 import Symantic.Univariant.Trans
19 import qualified Symantic.Parser as P
20 import qualified Symantic.Parser.Haskell as H
22 type Parser a = P.Parser Text.Text a
24 nandIdentStart :: Char -> Bool
25 nandIdentStart c = isAlpha c || c == '_'
27 nandIdentLetter :: Char -> Bool
28 nandIdentLetter c = isAlphaNum c || c == '_'
30 nandUnreservedName :: String -> Bool
31 nandUnreservedName = \s -> not (Set.member s keys)
33 keys = Set.fromList ["if", "else", "while", "function", "var"]
35 nandStringLetter :: Char -> Bool
36 nandStringLetter c = (c /= '"') && (c /= '\\') && (c > '\026')
38 nandlang :: forall repr.
39 P.Grammar Char repr =>
41 nandlang = whitespace P.*> P.skipMany funcdef P.<* P.eof
46 identifier = P.try (identStart P.*> P.skipMany identLetter) P.*> whitespace
48 variable = identifier P.*> P.optional index
51 literal = bit P.<|> charLit
53 keyword :: String -> repr ()
54 keyword s = P.try (P.string s P.*> notIdentLetter) P.*> whitespace
56 identStart = P.satisfy
57 [P.ErrorItemLabel "identStart"]
58 (trans (H.ValueCode nandIdentStart [||nandIdentStart||]))
59 identLetter = P.satisfy
60 [P.ErrorItemLabel "identLetter"]
61 (trans (H.ValueCode nandIdentLetter [||nandIdentLetter||]))
62 notIdentLetter = P.negLook identLetter
65 bit = (P.char '0' P.<|> P.char '1') P.*> whitespace
71 charLit = P.between (P.char '\'') (symbol '\'') charChar
74 charChar = P.void (P.satisfy
75 [P.ErrorItemLabel "Char"]
76 (trans (H.ValueCode nandStringLetter [||nandStringLetter||]))) P.<|> esc
79 esc = P.char '\\' P.*> P.void (P.oneOf "0tnvfr")
82 expr = nandexpr P.*> P.skipMany (symbol '!' P.*> nandexpr)
85 nandexpr = literal P.<|> funccallOrVar
87 funccallOrVar :: repr ()
88 funccallOrVar = identifier P.*> P.optional (parens exprlist P.<|> index)
90 exprlist = commaSep expr
91 exprlist1 = commaSep1 expr
92 varlist = commaSep variable
93 varlist1 = commaSep1 variable
95 funcparam = varlist P.*> P.optional (symbol ':' P.*> varlist)
96 varstmt = P.optional (keyword "var") P.*> varlist1 P.*> symbol '=' P.*> exprlist1 P.<* semi
97 ifstmt = keyword "if" P.*> expr P.*> block P.*> P.optional (keyword "else" P.*> block)
98 whilestmt = keyword "while" P.*> expr P.*> block
99 statement = ifstmt P.<|> whilestmt P.<|> P.try varstmt P.<|> expr P.<* semi
100 block = braces (P.skipMany statement)
101 funcdef = keyword "function" P.*> identifier P.*> parens funcparam P.*> block
104 decimal = number (P.oneOf ['0'..'9'])
105 -- hexadecimal = P.oneOf "xX" P.*> number (P.oneOf (['a'..'f'] <> ['A'..'F'] <> ['0'..'9']))
106 -- octal = P.oneOf "oO" P.*> number (P.oneOf ['0'..'7'])
107 number :: repr a -> repr ()
108 number digit = P.skipSome digit
110 symbol :: Char -> repr Char
111 symbol c = P.char c P.<* whitespace
112 parens :: repr a -> repr a
113 parens = P.between (symbol '(') (symbol ')')
114 brackets :: repr a -> repr a
115 brackets = P.between (symbol '[') (symbol ']')
116 braces :: repr a -> repr a
117 braces = P.between (symbol '{') (symbol '}')
122 commaSep :: repr a -> repr ()
123 commaSep p = P.optional (commaSep1 p)
124 commaSep1 :: repr a -> repr ()
125 commaSep1 p = p P.*> P.skipMany (comma P.*> p)
128 space = P.void (P.satisfy
129 [P.ErrorItemLabel "space"]
130 (trans (H.ValueCode isSpace [||isSpace||])))
131 whitespace :: repr ()
132 whitespace = P.skipMany (spaces P.<|> oneLineComment)
134 spaces = P.skipSome space
135 oneLineComment :: repr ()
136 oneLineComment = P.void (P.string "//" P.*> P.skipMany (P.satisfy
137 [P.ErrorItemLabel "oneLineComment"]
138 (trans (H.ValueCode (/= '\n') [||(/= '\n')||]))))