ParserExpr.fs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. module Qsp.Parser.Expr
  2. open FParsec
  3. open FsharpMyExtension
  4. open FsharpMyExtension.Either
  5. open Qsp
  6. open Qsp.Ast
  7. open Qsp.Parser.Generic
  8. open Qsp.Tokens
  9. let pbinaryOperator : _ Parser =
  10. [
  11. Defines.exprNamedOperators |> List.map (fun (x, _, _) -> x)
  12. Defines.keywords |> List.map fst
  13. ]
  14. |> List.concat
  15. |> List.sortDescending
  16. |> List.map pstringCI
  17. |> choice
  18. /// берёт только то, что начинается с `#` или `$`
  19. let pexplicitVar varHighlightKind : _ Parser =
  20. let isIdentifierFirstChar c = isLetter c || c = '_'
  21. let p = many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
  22. // TODO: или просто `many1Satisfy isIdentifierChar` ?
  23. let varType =
  24. choice [
  25. pchar '#' >>% ExplicitNumericType
  26. pchar '$' >>% StringType
  27. ]
  28. (getPosition .>>.? varType) .>>. (p .>>. getPosition)
  29. >>= fun ((p1, typ), (varName, p2)) ->
  30. let range = toRange p1 p2
  31. let msg =
  32. match typ with
  33. | StringType ->
  34. Defines.vars
  35. |> Map.tryFind (sprintf "$%s" (varName.ToLower()))
  36. |> function
  37. | Some dscr -> dscr
  38. | None -> "Пользовательская глобальная переменная строчного типа"
  39. | ExplicitNumericType ->
  40. Defines.vars
  41. |> Map.tryFind (sprintf "#%s" (varName.ToLower()))
  42. |> function
  43. | Some dscr -> dscr
  44. | None -> "Пользовательская глобальная переменная числового типа"
  45. | ImplicitNumericType -> failwith "Not Implemented"
  46. appendToken2 Tokens.Variable range
  47. >>. appendHover2 msg range
  48. >>. appendVarHighlight range (typ, varName) varHighlightKind
  49. >>. preturn (typ, varName)
  50. type ProcOrFunc =
  51. | Procedure of string
  52. | Function of string
  53. let notFollowedByBinOpIdent =
  54. // конечно, тут нужно объяснить пользователю, почему именно нельзя использовать то или иное слово
  55. // проще назвать, что допустимо
  56. // let p =
  57. // choice [
  58. // spaces1
  59. // skipChar '"'
  60. // skipChar '''
  61. // eof
  62. // ]
  63. // let followedVarCont =
  64. // followedBy (satisfy (fun c -> isDigit c || c = '_' || c = '.'))
  65. let p =
  66. pbinaryOperator
  67. .>> (skipSatisfy (not << isIdentifierChar)
  68. <|> eof)
  69. let p2 =
  70. notFollowedByL p "идентификатор, а не строковый бинарный оператор"
  71. >>. ident
  72. // runStateEither p2 emptyState "no"
  73. // runStateEither p2 emptyState "no " // нельзя
  74. // runStateEither p2 emptyState "node" // можно
  75. // runStateEither p2 emptyState "foobar" // можно
  76. p2
  77. let ws =
  78. ws
  79. >>. skipMany
  80. (appendToken TokenType.Underscore (pchar '_')
  81. >>? ((ws1 >>? skipNewline) <|> skipNewline) >>. spaces)
  82. let term expr =
  83. let pterm, ptermRef = createParserForwardedToRef()
  84. let pcallFuncOrArrOrVar =
  85. let pbraket = bet_ws '[' ']' (sepBy expr (skipChar ',' >>. ws))
  86. let pBracesArgs =
  87. bet_ws '(' ')' (sepBy expr (pchar ',' >>. ws))
  88. let pcallFunctionOrArrOrVar =
  89. let pimplicitVar =
  90. notFollowedByBinOpIdent |>> fun x -> ImplicitNumericType, x
  91. let pexplicitVar =
  92. let isIdentifierFirstChar c = isLetter c || c = '_'
  93. let p = many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
  94. // TODO: или просто `many1Satisfy isIdentifierChar` ?
  95. let varType =
  96. choice [
  97. pchar '#' >>% ExplicitNumericType
  98. pchar '$' >>% StringType
  99. ]
  100. varType .>>. p
  101. tuple2
  102. (applyRange (pexplicitVar <|> pimplicitVar) .>> ws)
  103. ((pBracesArgs |>> fun args -> TokenType.Function, fun (typ', name) -> Func(name, args))
  104. // Невозможно, поскольку неоднозначно трактуется `f+1` => `f(+1)` или `f + 1`
  105. // <|> (pterm |>> fun arg -> TokenType.Function, fun (typ', name) -> Func(name, [arg]))
  106. <|> (pbraket
  107. |>> fun arg ->
  108. let f (varType, nameVar) = Arr((varType, nameVar), arg)
  109. TokenType.Variable, f)
  110. <|>% (TokenType.Variable, fun (varType, nameVar) -> Var(varType, nameVar)))
  111. >>= fun ((range, (varType, name)), (tokenType, f)) ->
  112. match tokenType with
  113. | TokenType.Function ->
  114. match f (varType, name) with
  115. | Func(name, args) as func ->
  116. let p =
  117. [
  118. "Такой функции нет, а если есть, то напишите мне, автору расширения, пожалуйста, и я непременно добавлю."
  119. "Когда-нибудь добавлю: 'Возможно, вы имели ввиду: ...'"
  120. ]
  121. |> String.concat "\n"
  122. |> appendSemanticError range
  123. p
  124. >>. appendToken2 tokenType range
  125. >>% func
  126. | func -> preturn func
  127. | TokenType.Variable ->
  128. let desc =
  129. match varType with
  130. | StringType ->
  131. Defines.vars
  132. |> Map.tryFind (sprintf "$%s" (name.ToLower()))
  133. |> function
  134. | Some dscr -> dscr
  135. | None -> "Пользовательская глобальная переменная строчного типа"
  136. | ExplicitNumericType ->
  137. Defines.vars
  138. |> Map.tryFind (sprintf "#%s" (name.ToLower()))
  139. |> function
  140. | Some dscr -> dscr
  141. | None -> "Пользовательская глобальная переменная числового типа"
  142. | ImplicitNumericType ->
  143. Defines.vars
  144. |> Map.tryFind (name.ToLower())
  145. |> function
  146. | Some dscr -> dscr
  147. | None ->
  148. "Пользовательская глобальная переменная числового типа"
  149. appendHover2 desc range
  150. >>. appendToken2 tokenType range
  151. >>. appendVarHighlight range (varType, name) VarHighlightKind.ReadAccess
  152. >>% f (varType, name)
  153. | tokenType ->
  154. appendToken2 tokenType range
  155. >>% f (varType, name)
  156. let pPreDefFunc =
  157. Defines.functions
  158. |> Seq.sortByDescending (fun (KeyValue(name, _)) -> name) // для жадности
  159. |> Seq.map (fun (KeyValue(name, (dscr, sign))) ->
  160. applyRange (pstringCI name .>>? notFollowedVarCont)
  161. >>= fun (range, name) ->
  162. appendToken2 TokenType.Function range
  163. >>. appendHover2 dscr range
  164. >>% (name, range, sign)
  165. )
  166. |> List.ofSeq
  167. |> choice
  168. pPreDefFunc .>> ws .>>. (pBracesArgs <|> (pterm |>> List.singleton) <|>% [])
  169. >>= fun ((name, range, (sign, returnType)), args) ->
  170. let p =
  171. args
  172. |> Array.ofList
  173. |> Defines.getFuncByOverloadType sign
  174. |> function
  175. | None ->
  176. let msg =
  177. Defines.Show.printFuncSignature name returnType sign
  178. |> sprintf "Ожидается одна из перегрузок:\n%s"
  179. appendSemanticError range msg
  180. | Some () ->
  181. preturn ()
  182. p
  183. >>% Func(name, args)
  184. <|> pcallFunctionOrArrOrVar
  185. let pval =
  186. choice [
  187. // TODO: `pbraces` — он точно нужен?
  188. stringLiteralWithToken expr |>> String
  189. appendToken TokenType.ConstantNumericInteger
  190. (pint32 |>> Int)
  191. ]
  192. |>> Val
  193. ptermRef := pval <|> pcallFuncOrArrOrVar
  194. pval <|> pcallFuncOrArrOrVar <|> bet_ws '(' ')' expr
  195. let pExprOld : _ Parser =
  196. let opp = new OperatorPrecedenceParser<Expr, unit, _>()
  197. let expr = opp.ExpressionParser
  198. opp.TermParser <- term expr .>> ws
  199. Op.ops
  200. |> Array.iter (fun (opTyp, (opName, isSymbolic)) ->
  201. let prec = Precedences.prec <| Precedences.OpB opTyp
  202. if isSymbolic then
  203. if opName = ">" then
  204. // внутри string есть подстановка `<<expr>>`, и эта условность нужна, чтобы не захватывать `>>`
  205. let p = notFollowedBy (pchar '>') >>. ws
  206. InfixOperator(opName, p, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  207. else
  208. InfixOperator(opName, ws, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  209. |> opp.AddOperator
  210. else
  211. let afterStringParser = notFollowedVarCont >>. ws
  212. InfixOperator(opName, afterStringParser, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  213. |> opp.AddOperator
  214. InfixOperator(opName.ToUpper(), afterStringParser, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  215. |> opp.AddOperator
  216. )
  217. Reflection.Reflection.unionEnum
  218. |> Array.iter (fun unT ->
  219. let afterStringParser opName =
  220. if String.forall isLetter opName then
  221. notFollowedVarCont
  222. >>. ws
  223. else
  224. ws
  225. let unarOp = UnarOp.toString unT
  226. let prec = Precedences.prec <| Precedences.PrefB unT
  227. PrefixOperator(unarOp, afterStringParser unarOp, prec, false, fun x -> UnarExpr(unT, x))
  228. |> opp.AddOperator
  229. )
  230. expr <?> "expr"
  231. let pExprNew : _ Parser =
  232. let pExpr, pExprRef = createParserForwardedToRef()
  233. let term = term pExpr
  234. let pchar c typ =
  235. appendToken typ (pchar c)
  236. let pstringCI c typ =
  237. appendToken typ (pstringCI c)
  238. let pstring c typ =
  239. appendToken typ (pstring c)
  240. let pNeg =
  241. pchar '-' (TokenType.UnaryOperator Neg) >>. ws >>. term
  242. |>> fun e1 -> UnarExpr(Neg, e1)
  243. let pProd =
  244. chainl1 (pNeg <|> term .>> ws)
  245. ((pchar '*' (TokenType.BinaryOperator Times) >>% Times
  246. <|> (pchar '/' (TokenType.BinaryOperator Divide) >>% Divide))
  247. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  248. let pMod =
  249. chainl1 (pProd .>> ws)
  250. ((pstringCI "mod" (TokenType.BinaryOperator Mod) >>? notFollowedVarCont >>. ws >>% Mod)
  251. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  252. let pSum =
  253. chainl1 (pMod .>> ws)
  254. ((pchar '+' (TokenType.BinaryOperator Plus) >>% Plus
  255. <|> (pchar '-' (TokenType.BinaryOperator Minus) >>% Minus))
  256. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  257. let pCompare pNo =
  258. chainl1 (pNo <|> pSum .>> ws)
  259. (choice [
  260. pstring "=>" (TokenType.BinaryOperator Eg) >>% Eg
  261. pstring "=<" (TokenType.BinaryOperator El) >>% El
  262. pchar '=' (TokenType.BinaryOperator Eq) >>% Eq
  263. pstring "<>" (TokenType.BinaryOperator Ne) >>% Ne
  264. pstring "<=" (TokenType.BinaryOperator Le) >>% Le
  265. pchar '<' (TokenType.BinaryOperator Lt) >>% Lt
  266. pstring ">=" (TokenType.BinaryOperator Ge) >>% Ge
  267. pchar '>' (TokenType.BinaryOperator Gt) .>>? notFollowedBy (FParsec.CharParsers.pchar '>') >>% Gt // чтобы исключить `>>`
  268. pchar '!' (TokenType.BinaryOperator Bang) >>% Bang
  269. ]
  270. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  271. let pObj pNo =
  272. let pObj =
  273. pstringCI "obj" TokenType.Procedure .>>? notFollowedVarCont >>% Obj
  274. <|> (pstringCI "loc" TokenType.Procedure .>>? notFollowedVarCont >>% Loc)
  275. .>> ws .>>. pCompare pNo
  276. |>> fun (op, e1) -> UnarExpr(op, e1)
  277. pObj <|> pCompare pNo .>> ws
  278. let pNo =
  279. // TODO: `no` — ассоциативный оператор, потому допустимо такое: `no (no -1)`
  280. let pNo, pNoRef = createParserForwardedToRef()
  281. pNoRef :=
  282. pstringCI "no" TokenType.Procedure >>? notFollowedVarCont >>. ws >>. pObj pNo
  283. |>> fun e1 -> UnarExpr(No, e1)
  284. pNo <|> pObj pNo .>> ws
  285. let pAnd =
  286. chainl1 (pNo .>> ws)
  287. ((pstringCI "and" TokenType.Procedure >>? notFollowedVarCont >>. ws >>% And)
  288. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  289. let pOr =
  290. chainl1 (pAnd .>> ws)
  291. ((pstringCI "or" TokenType.Procedure >>? notFollowedVarCont >>. ws >>% Or)
  292. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  293. pExprRef := pOr
  294. pExpr
  295. let pexpr = pExprNew