ParserExpr.fs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 term expr =
  78. let pcallFuncOrArrOrVar =
  79. let pbraket = bet_ws '[' ']' (sepBy expr (skipChar ',' >>. ws))
  80. let pexplicitVar =
  81. pexplicitVar VarHighlightKind.ReadAccess .>> ws .>>. opt pbraket
  82. |>> fun (var, arr) ->
  83. match arr with
  84. | Some args -> Arr(var, args)
  85. | None -> Var var
  86. let pBracesArgs =
  87. bet_ws '(' ')' (sepBy expr (pchar ',' >>. ws))
  88. let pcallFunctionOrArrOrVar =
  89. tuple2
  90. (applyRange notFollowedByBinOpIdent
  91. .>> ws)
  92. ((pBracesArgs |>> fun args -> TokenType.Function, fun name -> Func(name, args))
  93. <|> (pbraket
  94. |>> fun arg ->
  95. let f name = Arr((ImplicitNumericType, name), arg)
  96. TokenType.Variable, f)
  97. <|>% (TokenType.Variable, fun name -> Var(ImplicitNumericType, name)))
  98. >>= fun ((range, name), (tokenType, f)) ->
  99. match tokenType with
  100. | TokenType.Function ->
  101. match f name with
  102. | Func(name, args) as func ->
  103. let p =
  104. [
  105. "Такой функции нет, а если есть, то напишите мне, автору расширения, пожалуйста, и я непременно добавлю."
  106. "Когда-нибудь добавлю: 'Возможно, вы имели ввиду: ...'"
  107. ]
  108. |> String.concat "\n"
  109. |> appendSemanticError range
  110. p
  111. >>. appendToken2 tokenType range
  112. >>% func
  113. | func -> preturn func
  114. | TokenType.Variable ->
  115. let p =
  116. Defines.vars
  117. |> Map.tryFind (name.ToLower())
  118. |> function
  119. | Some dscr ->
  120. appendHover2 dscr range
  121. | None ->
  122. let dscr = "Пользовательская глобальная переменная числового типа"
  123. appendHover2 dscr range
  124. p
  125. >>. appendToken2 tokenType range
  126. >>. appendVarHighlight range (ImplicitNumericType, name) VarHighlightKind.ReadAccess
  127. >>% f name
  128. | tokenType ->
  129. appendToken2 tokenType range
  130. >>% f name
  131. let pPreDefFunc =
  132. Defines.functions
  133. |> Seq.sortByDescending (fun (KeyValue(name, _)) -> name) // для жадности
  134. |> Seq.map (fun (KeyValue(name, (dscr, sign))) ->
  135. applyRange (pstringCI name .>>? notFollowedVarCont)
  136. >>= fun (range, name) ->
  137. appendToken2 TokenType.Function range
  138. >>. appendHover2 dscr range
  139. >>% (name, range, sign)
  140. )
  141. |> List.ofSeq
  142. |> choice
  143. pPreDefFunc .>> ws .>>. (opt pBracesArgs |>> Option.defaultValue [])
  144. >>= fun ((name, range, (sign, returnType)), args) ->
  145. let p =
  146. args
  147. |> Array.ofList
  148. |> Defines.getFuncByOverloadType sign
  149. |> function
  150. | None ->
  151. let msg =
  152. Defines.Show.printFuncSignature name returnType sign
  153. |> sprintf "Ожидается одна из перегрузок:\n%s"
  154. appendSemanticError range msg
  155. | Some () ->
  156. preturn ()
  157. p
  158. >>% Func(name, args)
  159. <|> pexplicitVar
  160. <|> pcallFunctionOrArrOrVar
  161. let pval =
  162. choice [
  163. // TODO: `pbraces` — он точно нужен?
  164. stringLiteralWithToken expr |>> String
  165. appendToken TokenType.ConstantNumericInteger
  166. (pint32 |>> Int)
  167. ]
  168. |>> Val
  169. pval <|> pcallFuncOrArrOrVar <|> bet_ws '(' ')' expr
  170. let pExprOld : _ Parser =
  171. let opp = new OperatorPrecedenceParser<Expr, unit, _>()
  172. let expr = opp.ExpressionParser
  173. opp.TermParser <- term expr .>> ws
  174. Op.ops
  175. |> Array.iter (fun (opTyp, (opName, isSymbolic)) ->
  176. let prec = Precedences.prec <| Precedences.OpB opTyp
  177. if isSymbolic then
  178. if opName = ">" then
  179. // внутри string есть подстановка `<<expr>>`, и эта условность нужна, чтобы не захватывать `>>`
  180. let p = notFollowedBy (pchar '>') >>. ws
  181. InfixOperator(opName, p, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  182. else
  183. InfixOperator(opName, ws, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  184. |> opp.AddOperator
  185. else
  186. let afterStringParser = notFollowedVarCont >>. ws
  187. InfixOperator(opName, afterStringParser, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  188. |> opp.AddOperator
  189. InfixOperator(opName.ToUpper(), afterStringParser, prec, Associativity.Left, fun x y -> Expr(opTyp, x, y))
  190. |> opp.AddOperator
  191. )
  192. Reflection.Reflection.unionEnum
  193. |> Array.iter (fun unT ->
  194. let afterStringParser opName =
  195. if String.forall isLetter opName then
  196. notFollowedVarCont
  197. >>. ws
  198. else
  199. ws
  200. let unarOp = UnarOp.toString unT
  201. let prec = Precedences.prec <| Precedences.PrefB unT
  202. PrefixOperator(unarOp, afterStringParser unarOp, prec, false, fun x -> UnarExpr(unT, x))
  203. |> opp.AddOperator
  204. )
  205. expr <?> "expr"
  206. let pExprNew : _ Parser =
  207. let pExpr, pExprRef = createParserForwardedToRef()
  208. let term = term pExpr
  209. let pchar c typ =
  210. appendToken typ (pchar c)
  211. let pstringCI c typ =
  212. appendToken typ (pstringCI c)
  213. let pstring c typ =
  214. appendToken typ (pstring c)
  215. let pNeg =
  216. pchar '-' TokenType.OperatorArithmetic >>. ws >>. term
  217. |>> fun e1 -> UnarExpr(Neg, e1)
  218. let pProd =
  219. chainl1 (pNeg <|> term .>> ws)
  220. ((pchar '*' TokenType.OperatorArithmetic >>% Times
  221. <|> (pchar '/' TokenType.OperatorArithmetic >>% Divide))
  222. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  223. let pMod =
  224. chainl1 (pProd .>> ws)
  225. ((pstringCI "mod" TokenType.OperatorArithmetic >>? notFollowedVarCont >>. ws >>% Mod)
  226. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  227. let pSum =
  228. chainl1 (pMod .>> ws)
  229. ((pchar '+' TokenType.OperatorArithmetic >>% Plus
  230. <|> (pchar '-' TokenType.OperatorArithmetic >>% Minus))
  231. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  232. let pCompare pNo =
  233. chainl1 (pNo <|> pSum .>> ws)
  234. (choice [
  235. pstring "=>" TokenType.OperatorComparison >>% Eg
  236. pstring "=<" TokenType.OperatorComparison >>% El
  237. pchar '=' TokenType.OperatorRelational >>% Eq
  238. pstring "<>" TokenType.OperatorRelational >>% Ne
  239. pstring "<=" TokenType.OperatorComparison >>% Le
  240. pchar '<' TokenType.OperatorComparison >>% Lt
  241. pstring ">=" TokenType.OperatorComparison >>% Ge
  242. pchar '>' TokenType.OperatorComparison .>>? notFollowedBy (FParsec.CharParsers.pchar '>') >>% Gt // чтобы исключить `>>`
  243. pchar '!' TokenType.OperatorRelational >>% Bang
  244. ]
  245. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  246. let pObj pNo =
  247. let pObj =
  248. pstringCI "obj" TokenType.Procedure .>>? notFollowedVarCont >>% Obj
  249. <|> (pstringCI "loc" TokenType.Procedure .>>? notFollowedVarCont >>% Loc)
  250. .>> ws .>>. pCompare pNo
  251. |>> fun (op, e1) -> UnarExpr(op, e1)
  252. pObj <|> pCompare pNo .>> ws
  253. let pNo =
  254. // TODO: `no` — ассоциативный оператор, потому допустимо такое: `no (no -1)`
  255. let pNo, pNoRef = createParserForwardedToRef()
  256. pNoRef :=
  257. pstringCI "no" TokenType.Procedure >>? notFollowedVarCont >>. ws >>. pObj pNo
  258. |>> fun e1 -> UnarExpr(No, e1)
  259. pNo <|> pObj pNo .>> ws
  260. let pAnd =
  261. chainl1 (pNo .>> ws)
  262. ((pstringCI "and" TokenType.Procedure >>? notFollowedVarCont >>. ws >>% And)
  263. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  264. let pOr =
  265. chainl1 (pAnd .>> ws)
  266. ((pstringCI "or" TokenType.Procedure >>? notFollowedVarCont >>. ws >>% Or)
  267. .>> ws |>> fun op e1 e2 -> Expr(op, e1, e2))
  268. pExprRef := pOr
  269. pExpr
  270. let pexpr = pExprNew