ParserExpr.fs 12 KB

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