Test.fs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. open FsharpMyExtension
  2. open FsharpMyExtension
  3. open FsharpMyExtension.Either
  4. open FParsec
  5. #if INTERACTIVE
  6. #load @"..\QSParse\Tokens.fs"
  7. #load @"..\QSParse\Ast.fs"
  8. #load @"..\QSParse\Defines.fs"
  9. #load @"..\QSParse\Show.fs"
  10. #load @"..\QSParse\ParserGeneric.fs"
  11. #load @"..\QSParse\ParserExpr.fs"
  12. #load @"..\QSParse\Parsec.fs"
  13. #endif
  14. open Qsp
  15. open Qsp.Ast
  16. open Qsp.Parser.Generic
  17. open Qsp.Parser.Expr
  18. open Fuchu
  19. [<Tests>]
  20. let pexprTest =
  21. let runExpr str =
  22. runStateEither pexpr Qsp.Parser.Generic.emptyState str
  23. |> snd
  24. let sprintExpr =
  25. Show.simpleShowExpr (failwithf "showStmtsInline not implemented %A")
  26. >> FsharpMyExtension.ShowList.show
  27. let runExprShow str =
  28. runExpr str
  29. |> Either.map sprintExpr
  30. let equalWithShow (exp:Expr) (act:Either<_, Expr>) =
  31. match act with
  32. | Left _ ->
  33. failtestf "%A" act
  34. | Right act ->
  35. if exp <> act then
  36. failtestf "Expected:\n%A\n\"%s\"\n\nActual:\n%A\n\"%s\"" exp (sprintExpr exp) act (sprintExpr act)
  37. let testf input exp =
  38. testCase input <| fun () ->
  39. equalWithShow exp (runExpr input)
  40. testList "pexpr test" [
  41. testCase "строчные бинарные операторы и названия переменных, которые начинаются с них" <| fun () ->
  42. let input = "notFollowedBy" // Уж точно не должно быть "no tFollowedBy"
  43. let exp =
  44. Var (NumericType, "notFollowedBy")
  45. Assert.Equal("", Right exp, runExpr input)
  46. testCase "строчные бинарные операторы и названия переменных, которые начинаются с них" <| fun () ->
  47. let input = "object"
  48. let exp =
  49. Var (NumericType, "object")
  50. Assert.Equal("", Right exp, runExpr input)
  51. testCase "строчные бинарные операторы и названия переменных, которые начинаются с них" <| fun () ->
  52. let input = "obj something"
  53. let exp =
  54. UnarExpr (Obj, Var (NumericType, "something"))
  55. Assert.Equal("", Right exp, runExpr input)
  56. let input = "var1 and var2 and no var3 and obj var4"
  57. let exp =
  58. Expr
  59. (And,
  60. Expr
  61. (And,
  62. Expr
  63. (And, Var (NumericType, "var1"),
  64. Var (NumericType, "var2")),
  65. UnarExpr (No, Var (NumericType, "var3"))),
  66. UnarExpr (Obj, Var (NumericType, "var4")))
  67. testf input exp
  68. testCase "2" <| fun () ->
  69. let input = "var1[var1 + var2] and func(arg1, arg2[expr], x + y)"
  70. let exp = "var1[var1 + var2] and func(arg1, arg2[expr], x + y)"
  71. Assert.Equal("", Right exp, runExprShow input)
  72. testCase "3" <| fun () ->
  73. let input = "a = 10 or b = 20 and c = 30"
  74. let exp = "(a = 10) or ((b = 20) and (c = 30))"
  75. Assert.Equal("", Right exp, runExprShow input)
  76. testCase "4" <| fun () ->
  77. let input = "a = pstam> (pmaxstam/4)*2 and pstam <= (pmaxstam/4)*3"
  78. let exp = "((a = pstam) > ((pmaxstam / 4) * 2)) and (pstam <= ((pmaxstam / 4) * 3))"
  79. Assert.Equal("", Right exp, runExprShow input)
  80. testCase "no obj 'apple'" <| fun () ->
  81. let input = "no obj 'apple'"
  82. let exp =
  83. UnarExpr (No, UnarExpr (Obj, Val (String [[StringKind "apple"]])))
  84. Assert.Equal("", Right exp, runExpr input)
  85. let input = "- x"
  86. let exp =
  87. UnarExpr (Neg, Var (NumericType, "x"))
  88. testf input exp
  89. let input = "-x + -y"
  90. let exp =
  91. Expr
  92. (Plus, UnarExpr (Neg, Var (NumericType, "x")),
  93. UnarExpr (Neg, Var (NumericType, "y")))
  94. testf input exp
  95. let input =
  96. [
  97. "x + _"
  98. " "
  99. " _"
  100. " _"
  101. ""
  102. " z + y"
  103. ] |> String.concat "\n"
  104. let exp =
  105. Expr
  106. (Plus,
  107. Expr (Plus, Var (NumericType, "x"), Var (NumericType, "z")),
  108. Var (NumericType, "y"))
  109. testf input exp
  110. let input =
  111. "input 'How do you do?'"
  112. let exp =
  113. Func (Predef Defines.Input, [Val (String [[StringKind "How do you do?"]])])
  114. testf input exp
  115. ]
  116. // #load "Parsec.fs"
  117. [<Tests>]
  118. let assignTest =
  119. let runExpr str =
  120. Qsp.Parser.Generic.runStateEither (Qsp.Parser.Main.pAssign FParsec.Primitives.pzero) Qsp.Parser.Generic.emptyState str
  121. |> snd
  122. testList "assignTest" [
  123. testCase "implicit assign implicit var" <| fun () ->
  124. let input = "x = 21 + 21"
  125. let exp =
  126. (Assign
  127. (false, AssignVar (NumericType, "x"),
  128. Expr (Plus, Val (Int 21), Val (Int 21))))
  129. Assert.Equal("", Right exp, runExpr input)
  130. testCase "implicit assign implicit array var" <| fun () ->
  131. let input = "x[expr] = 42"
  132. let exp =
  133. (Assign
  134. (false, AssignArr
  135. ((NumericType, "x"), Var (NumericType, "expr")),
  136. Val (Int 42)))
  137. Assert.Equal("", Right exp, runExpr input)
  138. testCase "implicit `-=` implicit var" <| fun () ->
  139. let input = "years -= 10"
  140. let exp =
  141. (Assign
  142. (false, AssignVar (NumericType, "years"),
  143. Expr (Minus, Var (NumericType, "years"), Val (Int 10))))
  144. Assert.Equal("", Right exp, runExpr input)
  145. testCase "implicit `-=` implicit var 2" <| fun () ->
  146. let input = "php -= 3*emdmg*2 - parm"
  147. let exp =
  148. (Assign
  149. (false, AssignVar (NumericType, "php"),
  150. Expr
  151. (Minus, Var (NumericType, "php"),
  152. Expr
  153. (Minus,
  154. Expr
  155. (Times,
  156. Expr (Times, Val (Int 3), Var (NumericType, "emdmg")),
  157. Val (Int 2)), Var (NumericType, "parm")))))
  158. Assert.Equal("", Right exp, runExpr input)
  159. testCase "5" <| fun () ->
  160. let input = "a = a = no -a > b"
  161. let exp =
  162. (Assign
  163. (false, AssignVar (NumericType, "a"),
  164. Expr
  165. (Eq, Var (NumericType, "a"),
  166. UnarExpr
  167. (No,
  168. Expr
  169. (Gt, UnarExpr (Neg, Var (NumericType, "a")),
  170. Var (NumericType, "b"))))))
  171. Assert.Equal("", Right exp, runExpr input)
  172. testCase "implicit assign explicit array var" <| fun () ->
  173. let input = "$x[expr] = 42"
  174. let exp =
  175. (Assign
  176. (false, AssignArr ((StringType, "x"), Var (NumericType, "expr")),
  177. Val (Int 42)))
  178. Assert.Equal("", Right exp, runExpr input)
  179. testCase "#x = 21 + 21" <| fun () ->
  180. let input = "#x = 21 + 21"
  181. let exp =
  182. (Assign
  183. (false, AssignVar (NumericType, "#x"),
  184. Expr (Plus, Val (Int 21), Val (Int 21))))
  185. Assert.Equal("", Right exp, runExpr input)
  186. testCase "`x[] = 1`" <| fun () ->
  187. let input = "x[] = 1"
  188. let exp =
  189. Assign (false, AssignArrAppend (NumericType, "x"), Val (Int 1))
  190. Assert.Equal("", Right exp, runExpr input)
  191. // ложные случаи:
  192. testCase "attempt assign function" <| fun () ->
  193. let input = "f(expr) = 42" // поскольку `=` — это одновременно и оператор присваивания и оператор равности, так что сойдет за выражение
  194. let exp =
  195. [
  196. "Error in Ln: 1 Col: 1"
  197. "f(expr) = 42"
  198. "^"
  199. "Expecting: '$', 'let' (case-insensitive) or 'set'"
  200. "(case-insensitive)"
  201. ""
  202. "The parser backtracked after:"
  203. " Error in Ln: 1 Col: 2"
  204. " f(expr) = 42"
  205. " ^"
  206. " Expecting: '*=', '+=', '-=', '/=', '=', '[' or '_'"
  207. ""
  208. ] |> String.concat "\r\n"
  209. Assert.Equal("", Left exp, runExpr input)
  210. testCase "attempt assign var without body" <| fun () ->
  211. let input = "justName"
  212. let act =
  213. runExpr input
  214. |> Option.ofEither
  215. Assert.None("", act)
  216. testCase "attempt assign var without body space" <| fun () ->
  217. let input = "justName "
  218. let act =
  219. runExpr input
  220. |> Option.ofEither
  221. Assert.None("", act)
  222. testCase "just `x[expr]`" <| fun () ->
  223. let input = "x[expr]"
  224. let act =
  225. runExpr input
  226. |> Option.ofEither
  227. Assert.None("", act)
  228. ]
  229. [<Tests>]
  230. let stringLiteralTest =
  231. testList "stringLiteralTest" [
  232. testCase "1" <| fun () ->
  233. Assert.Equal("", Right " ", runEither stringLiteral "\" \"")
  234. testCase "2" <| fun () ->
  235. Assert.Equal("", Right "\"", runEither stringLiteral "\"\"\"\"")
  236. testCase "3" <| fun () ->
  237. Assert.Equal("", Right "\"'\"", runEither stringLiteral "\"\"\"'\"\"\"")
  238. testCase "5" <| fun () ->
  239. Assert.Equal("", Right "", runEither stringLiteral "''")
  240. testCase "6" <| fun () ->
  241. Assert.Equal("", Right "'", runEither stringLiteral "''''")
  242. testCase "4" <| fun () ->
  243. Assert.Equal("", Right "\"", runEither stringLiteral "'\"'")
  244. testCase "braces1" <| fun () ->
  245. Assert.Equal("", Right "abc", runEither stringLiteral "{abc}")
  246. testCase "braces escaped" <| fun () ->
  247. Assert.Equal("", Right "}", runEither stringLiteral "{}}}")
  248. ]
  249. let emptyPos = NoEqualityPosition positionEmpty
  250. let emptyPoss x = x |> List.map (fun x -> emptyPos, x)
  251. let StaticStmts x =
  252. emptyPoss x
  253. |> StaticStmts
  254. let If(expr, thenBody, elseBody) =
  255. If(expr, emptyPoss thenBody, emptyPoss elseBody)
  256. let Act(exprs, thenBody) = Act(exprs, emptyPoss thenBody)
  257. let equalTwoPosStmt (note, stmt1, stmt2) =
  258. match stmt1, stmt2 with
  259. | Right stmt1', Right stmt2' ->
  260. if stmt1' <> stmt2' then
  261. failtestf "Expected:\n%A\n\nActual:\n%A\nWarning: ignores Position when comparing!" stmt1 stmt2
  262. | _ -> failtestf "Expected:\n%A\n\nActual:\n%A\nWarning: ignores Position when comparing!" stmt1 stmt2
  263. let exprEqual (note, expr1, expr2) =
  264. match expr1, expr2 with
  265. | Right expr1', Right expr2' ->
  266. if expr1' <> expr2' then
  267. failtestf "Expected:\n%A\n\nActual:\n%A\nWarning: ignores Position when comparing!" expr1 expr2
  268. | _ -> failtestf "Expected:\n%A\n\nActual:\n%A\nWarning: ignores Position when comparing!" expr1 expr2
  269. [<Tests>]
  270. let stringLiteralWithTokenTest =
  271. let runEither str =
  272. Qsp.Parser.Generic.runStateEither
  273. (stringLiteralWithToken pexpr)
  274. { Qsp.Parser.Generic.emptyState with
  275. PStmts = Parser.Main.pstmts
  276. }
  277. str
  278. |> snd
  279. let f str =
  280. [[StringKind str]]
  281. testList "stringLiteralWithTokenTest" [
  282. testCase "1" <| fun () ->
  283. Assert.Equal("", Right (f " "), runEither "\" \"")
  284. testCase "2" <| fun () ->
  285. Assert.Equal("", Right (f "\""), runEither "\"\"\"\"")
  286. testCase "3" <| fun () ->
  287. Assert.Equal("", Right (f "\"'\""), runEither "\"\"\"'\"\"\"")
  288. testCase "5" <| fun () ->
  289. Assert.Equal("", Right [[]], runEither "''")
  290. testCase "6" <| fun () ->
  291. Assert.Equal("", Right (f "'"), runEither "''''")
  292. testCase "4" <| fun () ->
  293. Assert.Equal("", Right (f "\""), runEither "'\"'")
  294. testCase "multiline `'` test" <| fun () ->
  295. let input =
  296. [
  297. "'"
  298. " a"
  299. "'"
  300. ] |> String.concat "\n"
  301. let exp =
  302. [
  303. []
  304. [ StringKind " a"]
  305. []
  306. ]
  307. Assert.Equal("", Right exp, runEither input)
  308. testCase "multiline `'` test2" <| fun () ->
  309. let input =
  310. [
  311. "'"
  312. " a"
  313. ""
  314. "b"
  315. "'"
  316. ] |> String.concat "\n"
  317. let exp =
  318. [
  319. []
  320. [ StringKind " a" ]
  321. []
  322. [ StringKind "b" ]
  323. []
  324. ]
  325. Assert.Equal("", Right exp, runEither input)
  326. testCase "test '<<''x''>>'" <| fun () ->
  327. let input = "'<<''x''>>'"
  328. let exp = [[ExprKind (Val (String [[StringKind "x"]]))]]
  329. Assert.Equal("", Right exp, runEither input)
  330. testCase "test '<<''<<''''x''''>>''>>'" <| fun () ->
  331. let input = "'<<''<<''''x''''>>''>>'"
  332. let exp = [[ExprKind (Val (String [[ExprKind (Val (String [[StringKind "x"]]))]]))]]
  333. Assert.Equal("", Right exp, runEither input)
  334. testCase "test '<<''<<''''<<''''''''x''''''''>>''''>>''>>'" <| fun () ->
  335. let input = "'<<''<<''''<<''''''''x''''''''>>''''>>''>>'"
  336. let exp =
  337. [[ExprKind
  338. (Val
  339. (String
  340. [[ExprKind
  341. (Val (String [[ExprKind (Val (String [[StringKind "x"]]))]]))]]))]]
  342. Assert.Equal("", Right exp, runEither input)
  343. testCase "test \"<<'x'>>\"" <| fun () ->
  344. let input = "\"<<'x'>>\""
  345. let exp = [[ExprKind (Val (String [[StringKind "x"]]))]]
  346. Assert.Equal("", Right exp, runEither input)
  347. testCase "test '<a href=\"exec:GT ''changes''\">changes</a>'" <| fun () ->
  348. let input = "'<a href=\"exec:GT ''changes''\">changes</a>'"
  349. let exp =
  350. [[HyperLinkKind
  351. (StaticStmts [Proc ("GT", [Val (String [[StringKind "changes"]])])],
  352. [[StringKind "changes"]])]]
  353. Assert.Equal("", Right exp, runEither input)
  354. testCase "test '<a href=\"exec: ''<<''x''>>''\">action</a>'" <| fun () ->
  355. let input = "'<a href=\"exec: ''<<''x''>>''\">action</a>'"
  356. let exp =
  357. [[HyperLinkKind (Raw " '<<'x'>>'", [[StringKind "action"]])]]
  358. Assert.Equal("", Right exp, runEither input)
  359. ]
  360. [<Tests>]
  361. let pbracesTests =
  362. let runEither str =
  363. Qsp.Parser.Generic.runStateEither
  364. (pbraces Tokens.TokenType.StringBraced)
  365. Qsp.Parser.Generic.emptyState
  366. str
  367. |> snd
  368. testList "stringLiteralWithTokenTest" [
  369. testCase "base" <| fun () ->
  370. Assert.Equal("", Right "", runEither "{}")
  371. testCase "braces1" <| fun () ->
  372. Assert.Equal("", Right "abc", runEither "{abc}")
  373. testCase "1" <| fun () ->
  374. let input =
  375. [
  376. "{"
  377. " asdf"
  378. " {"
  379. " asdf"
  380. " }"
  381. "}"
  382. ] |> String.concat "\n"
  383. let exp =
  384. [
  385. ""
  386. " asdf"
  387. " {"
  388. " asdf"
  389. " }"
  390. ""
  391. ] |> String.concat "\n"
  392. Assert.Equal("", Right exp, runEither input)
  393. ]
  394. [<Tests>]
  395. let pcallProcTests =
  396. let runStmts str =
  397. Qsp.Parser.Generic.runStateEither Qsp.Parser.Main.pcallProc Qsp.Parser.Generic.emptyState str
  398. |> snd
  399. testList "pcallProcTests" [
  400. testCase "pcallProcTests base" <| fun () ->
  401. let input = "someProc arg1"
  402. let exp =
  403. Proc ("someProc", [Var (NumericType, "arg1")])
  404. Assert.Equal("", Right exp, runStmts input)
  405. testCase "pcallProcTests base many args" <| fun () ->
  406. let input = "someProc z / 2, x + y"
  407. let exp =
  408. (Proc
  409. ("someProc",
  410. [Expr (Divide, Var (NumericType, "z"), Val (Int 2));
  411. Expr
  412. (Plus, Var (NumericType, "x"), Var (NumericType, "y"))]))
  413. Assert.Equal("", Right exp, runStmts input)
  414. testCase "pcallProcTests false with space" <| fun () ->
  415. let input = "someProc "
  416. // let exp =
  417. // [
  418. // "Error in Ln: 1 Col: 1"
  419. // "someProc "
  420. // "^"
  421. // ""
  422. // "The parser backtracked after:"
  423. // " Error in Ln: 1 Col: 10"
  424. // " someProc "
  425. // " ^"
  426. // " Note: The error occurred at the end of the input stream."
  427. // " Expecting: identifier, integer number (32-bit, signed), prefix operator, '\"',"
  428. // " '#', '$', '\\'', '(', '_' or '{'"
  429. // ""
  430. // ] |> String.concat "\r\n"
  431. // Assert.Equal("", Left exp, runStmts input)
  432. let act =
  433. runStmts input
  434. |> Option.ofEither
  435. Assert.None("", act)
  436. testCase "pcallProcTests false" <| fun () ->
  437. let input = "someProc"
  438. // let exp =
  439. // [
  440. // "Error in Ln: 1 Col: 1"
  441. // "someProc"
  442. // "^"
  443. // ""
  444. // "The parser backtracked after:"
  445. // " Error in Ln: 1 Col: 9"
  446. // " someProc"
  447. // " ^"
  448. // " Note: The error occurred at the end of the input stream."
  449. // " Unknown Error(s)"
  450. // ""
  451. // ] |> String.concat "\r\n"
  452. // Assert.Equal("", Left exp, runStmts input)
  453. let act =
  454. runStmts input
  455. |> Option.ofEither
  456. Assert.None("", act)
  457. testCase "*pl" <| fun () ->
  458. let input = "*pl"
  459. let exp = Proc ("*pl", [])
  460. Assert.Equal("", Right exp, runStmts input)
  461. testCase "*pl arg1, arg2" <| fun () ->
  462. let input = "*pl arg1, arg2"
  463. let exp =
  464. (Proc
  465. ("*pl",
  466. [Var (NumericType, "arg1"); Var (NumericType, "arg2")]))
  467. Assert.Equal("", Right exp, runStmts input)
  468. testCase "call `p2 x`, который начинается на заданный оператор `p`, но образует новый" <| fun () ->
  469. let input = "p2 x"
  470. let exp =
  471. Proc ("p2", [Var (NumericType, "x")])
  472. Assert.Equal("", Right exp, runStmts input)
  473. testCase "call ad-hoc `add obj`" <| fun () ->
  474. let input = "add obj"
  475. let exp =
  476. Proc ("addobj", [])
  477. Assert.Equal("", Right exp, runStmts input)
  478. testCase "call ad-hoc `close all`" <| fun () ->
  479. let input = "close all"
  480. let exp =
  481. Proc ("close all", [])
  482. Assert.Equal("", Right exp, runStmts input)
  483. ]
  484. let printStmts stmts =
  485. List.collect (Show.showStmt (Qsp.Show.UsingSpaces 4) Show.FormatConfig.Default) stmts
  486. |> ShowList.joinEmpty "\n"
  487. |> ShowList.show
  488. let printStmt stmt =
  489. Qsp.Show.showStmt (Qsp.Show.UsingSpaces 4) Show.FormatConfig.Default stmt
  490. |> ShowList.joinEmpty "\n"
  491. |> ShowList.show
  492. let StarPl arg = Proc("*pl", [arg])
  493. [<Tests>]
  494. let ifTests =
  495. let runStmts str =
  496. Qsp.Parser.Generic.runStateEither
  497. Qsp.Parser.Main.pstmt
  498. Qsp.Parser.Generic.emptyState str
  499. |> snd
  500. let runStmtsEof str =
  501. Qsp.Parser.Generic.runStateEither
  502. (Qsp.Parser.Main.pstmt .>> eof)
  503. Qsp.Parser.Generic.emptyState str
  504. |> snd
  505. testList "ifTests" [
  506. testCase "inline if" <| fun () ->
  507. let input =
  508. [
  509. "if expr: gt 'hall'"
  510. "'statement that not belong to construction'"
  511. ] |> String.concat "\n"
  512. let exp =
  513. (emptyPos, If
  514. (Var (NumericType, "expr"), [Proc ("gt", [Val (String [[StringKind "hall"]])])],
  515. []))
  516. equalTwoPosStmt("", Right exp, runStmts input)
  517. testCase "inline if 2" <| fun () ->
  518. let input =
  519. [
  520. "if expr:"
  521. " if expr2: stmt1"
  522. " if expr3:"
  523. " stmt1"
  524. " else stmt2"
  525. " if expr4: stmt3"
  526. "elseif expr5:"
  527. " stmt6"
  528. "elseif expr6: stmt4"
  529. ] |> String.concat "\n"
  530. // tested
  531. let exp =
  532. If
  533. (Var (NumericType, "expr"),
  534. [If
  535. (Var (NumericType, "expr2"),
  536. [StarPl (Var (NumericType, "stmt1"))], []);
  537. If
  538. (Var (NumericType, "expr3"),
  539. [StarPl (Var (NumericType, "stmt1"))],
  540. [StarPl (Var (NumericType, "stmt2"))]);
  541. If
  542. (Var (NumericType, "expr4"),
  543. [StarPl (Var (NumericType, "stmt3"))], [])],
  544. [If
  545. (Var (NumericType, "expr5"),
  546. [StarPl (Var (NumericType, "stmt6"))],
  547. [If
  548. (Var (NumericType, "expr6"),
  549. [StarPl (Var (NumericType, "stmt4"))], [])])])
  550. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  551. testCase "simple if" <| fun () ->
  552. let input =
  553. [
  554. "if expr:"
  555. " someStmt"
  556. "end"
  557. ] |> String.concat "\n"
  558. let exp =
  559. (If
  560. (Var (NumericType, "expr"),
  561. [StarPl (Var (NumericType, "someStmt"))], []))
  562. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  563. testCase "elseif test" <| fun () ->
  564. let input =
  565. [
  566. "if expr1:"
  567. " stmt1"
  568. "elseif expr2:"
  569. " stmt2"
  570. "elseif expr3:"
  571. " stmt3"
  572. "else"
  573. " stmt4"
  574. "end"
  575. ] |> String.concat "\n"
  576. let exp =
  577. (If
  578. (Var (NumericType, "expr1"),
  579. [StarPl (Var (NumericType, "stmt1"))],
  580. [If
  581. (Var (NumericType, "expr2"),
  582. [StarPl (Var (NumericType, "stmt2"))],
  583. [If
  584. (Var (NumericType, "expr3"),
  585. [StarPl (Var (NumericType, "stmt3"))],
  586. [StarPl (Var (NumericType, "stmt4"))])])]))
  587. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  588. testCase "elseif test2" <| fun () ->
  589. let input =
  590. [
  591. "if expr1:"
  592. " stmt1"
  593. "elseif expr2:"
  594. " stmt2"
  595. "elseif expr3:"
  596. " stmt3"
  597. "end"
  598. ] |> String.concat "\n"
  599. let exp =
  600. (If
  601. (Var (NumericType, "expr1"),
  602. [StarPl (Var (NumericType, "stmt1"))],
  603. [If
  604. (Var (NumericType, "expr2"),
  605. [StarPl (Var (NumericType, "stmt2"))],
  606. [If
  607. (Var (NumericType, "expr3"),
  608. [StarPl (Var (NumericType, "stmt3"))], [])])]))
  609. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  610. testCase "another inline if" <| fun () ->
  611. let input =
  612. [
  613. "if expr:"
  614. "elseif expr: stmt"
  615. ] |> String.concat "\n"
  616. let exp =
  617. (If
  618. (Var (NumericType, "expr"), [],
  619. [If
  620. (Var (NumericType, "expr"),
  621. [StarPl (Var (NumericType, "stmt"))], [])]))
  622. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  623. testCase "elseif test2" <| fun () ->
  624. let input =
  625. [
  626. "if expr1:"
  627. " stmt1"
  628. "elseif expr2:"
  629. " stmt2"
  630. " if expr4:"
  631. " stmt4"
  632. " elseif expr5:"
  633. " stmt5"
  634. " end"
  635. " stmt6"
  636. "elseif expr3:"
  637. " stmt3"
  638. "end"
  639. ] |> String.concat "\n"
  640. let exp =
  641. (If
  642. (Var (NumericType, "expr1"),
  643. [StarPl (Var (NumericType, "stmt1"))],
  644. [If
  645. (Var (NumericType, "expr2"),
  646. [StarPl (Var (NumericType, "stmt2"));
  647. If
  648. (Var (NumericType, "expr4"),
  649. [StarPl (Var (NumericType, "stmt4"))],
  650. [If
  651. (Var (NumericType, "expr5"),
  652. [StarPl (Var (NumericType, "stmt5"))], [])]);
  653. StarPl (Var (NumericType, "stmt6"))],
  654. [If
  655. (Var (NumericType, "expr3"),
  656. [StarPl (Var (NumericType, "stmt3"))], [])])]))
  657. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  658. testCase "if" <| fun () ->
  659. let input =
  660. [
  661. "if expr1:"
  662. " stmt1"
  663. " act 'arg': pl"
  664. "elseif expr2:"
  665. " if expr3: stmt2 else stmt3 if expr4: stmt4 elseif expr5: stmt5"
  666. " stmt6"
  667. "end"
  668. ] |> String.concat "\n"
  669. let exp =
  670. (If
  671. (Var (NumericType, "expr1"),
  672. [StarPl (Var (NumericType, "stmt1"));
  673. Act ([Val (String [[StringKind "arg"]])], [Proc ("pl", [])])],
  674. [If
  675. (Var (NumericType, "expr2"),
  676. [If
  677. (Var (NumericType, "expr3"),
  678. [StarPl (Var (NumericType, "stmt2"))],
  679. [StarPl (Var (NumericType, "stmt3"));
  680. If
  681. (Var (NumericType, "expr4"),
  682. [StarPl (Var (NumericType, "stmt4"))],
  683. [If
  684. (Var (NumericType, "expr5"),
  685. [StarPl (Var (NumericType, "stmt5"))], [])])]);
  686. StarPl (Var (NumericType, "stmt6"))], [])]))
  687. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  688. ]
  689. [<Tests>]
  690. let stmtTests =
  691. let runStmts str =
  692. Qsp.Parser.Generic.runStateEither
  693. Qsp.Parser.Main.pstmt
  694. Qsp.Parser.Generic.emptyState str
  695. |> snd
  696. let runStmtsEof str =
  697. Qsp.Parser.Generic.runStateEither
  698. (Qsp.Parser.Main.pstmt .>> eof)
  699. Qsp.Parser.Generic.emptyState str
  700. |> snd
  701. testList "stmtTests" [
  702. testCase "inline act" <| fun () ->
  703. let input =
  704. [
  705. "act 'some act': gt 'hall'"
  706. "'statement that not belong to construction'"
  707. ] |> String.concat "\n"
  708. let exp =
  709. Act ([Val (String [[StringKind "some act"]])], [Proc ("gt", [Val (String [[StringKind "hall"]])])])
  710. equalTwoPosStmt("", Right (emptyPos, exp), runStmts input)
  711. // порядок разбора
  712. testCase "stmt `years -= 10`" <| fun () ->
  713. let input = "years -= 10"
  714. let exp =
  715. (Assign
  716. (false, AssignVar (NumericType, "years"),
  717. Expr (Minus, Var (NumericType, "years"), Val (Int 10))))
  718. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  719. testCase "call function as expression" <| fun () ->
  720. // f(1) — должно обрабатываться раньше, чем `callProc arg1, arg2`
  721. let input = "iif(somevar >= 2, 'thenBody', 'elseBody')"
  722. let exp =
  723. (StarPl
  724. (Func
  725. (Predef Defines.Iif,
  726. [Expr (Ge, Var (NumericType, "somevar"), Val (Int 2));
  727. Val (String [[StringKind "thenBody"]]); Val (String [[StringKind "elseBody"]])])))
  728. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  729. testCase "call procedure" <| fun () ->
  730. let input = "gt 'begin', 'real_character'"
  731. let exp =
  732. Proc ("gt", [Val (String [[StringKind "begin"]]); Val (String [[StringKind "real_character"]])])
  733. equalTwoPosStmt("", Right (emptyPos, exp), runStmtsEof input)
  734. // testCase "call " <| fun () ->
  735. // let input = "The(Lady), or, the, Tiger"
  736. // let exp =
  737. // CallSt ("gt", [Val (String "begin"); Val (String "real_character")])
  738. // Assert.Equal("", Right exp, runStmts input)
  739. ]
  740. module TestOnMocks =
  741. type T = Location list
  742. let enc = System.Text.Encoding.UTF8
  743. let startOnFile path =
  744. match Qsp.Parser.Main.startOnFile enc path with
  745. | Success(x, _, _) -> x
  746. | Failure(x, _, _) -> failwithf "%s\n%s" path x
  747. let replaceOrNot expPath actPath =
  748. printfn "\"%s\"\nnot equal\n\"%s\""
  749. (System.IO.Path.GetFullPath expPath)
  750. (System.IO.Path.GetFullPath actPath)
  751. let rec whileYOrN () =
  752. match System.Console.ReadKey().Key with
  753. | System.ConsoleKey.Y -> true
  754. | System.ConsoleKey.N -> false
  755. | x ->
  756. printfn "need (y/n) but %A" x
  757. whileYOrN ()
  758. printfn "Replace? (y/n)"
  759. let res = whileYOrN()
  760. if res then
  761. System.IO.File.Copy(actPath, expPath, true)
  762. printfn "replaced"
  763. res
  764. let addExpToPath path =
  765. path
  766. |> Path.changeFileNameWithoutExt (sprintf "%sExp")
  767. let outputDir = @"..\..\..\Mocks"
  768. let copyAsExp path =
  769. System.IO.File.Copy(path, addExpToPath path, true)
  770. let getPathActLocal (pathAct:string) =
  771. sprintf "%s\\%s" outputDir (System.IO.Path.GetFileName pathAct)
  772. |> fun x -> System.IO.Path.ChangeExtension(x, ".json")
  773. let showTest path =
  774. let srcPath = path
  775. let parseActPath = getPathActLocal srcPath
  776. let parseExpPath = addExpToPath parseActPath
  777. let getPath (path:string) =
  778. sprintf "%s\\%s" outputDir (System.IO.Path.GetFileName path)
  779. |> fun x -> System.IO.Path.ChangeExtension(x, ".qsps")
  780. let showActPath = getPath srcPath
  781. let showExpPath = addExpToPath showActPath
  782. let act =
  783. // if System.IO.File.Exists parseExpPath then
  784. // let src : T = Json.desf parseExpPath
  785. // src |> Qsp.Show.printLocs Qsp.Show.UsingTabs
  786. // else
  787. let act = startOnFile srcPath
  788. // act |> Json.serf parseExpPath
  789. // failwithf "\"%s\" не найден, потому пришлось его создать. Естественно, все тесты пошли коту под хвост." parseExpPath
  790. act |> Qsp.Show.printLocs Qsp.Show.UsingTabs Show.FormatConfig.Default
  791. let exp =
  792. if System.IO.File.Exists showExpPath then
  793. System.IO.File.ReadAllText showExpPath
  794. else
  795. System.IO.File.WriteAllText(showExpPath, act)
  796. failwithf "\"%s\" не найден, потому пришлось его создать. Естественно, все тесты пошли коту под хвост." showExpPath
  797. if exp <> act then
  798. System.IO.File.WriteAllText(showActPath, act)
  799. if replaceOrNot showExpPath showActPath then ()
  800. else failwithf "not pass"
  801. let mockTestList = "mock tests"
  802. [<Tests>]
  803. let showTests =
  804. let mocksDir = outputDir + @"\Src"
  805. let tests =
  806. if System.IO.Directory.Exists mocksDir then
  807. System.IO.Directory.GetFiles(mocksDir, "*.qsps")
  808. |> Array.map (fun path ->
  809. testCase (sprintf "'%s' test" (System.IO.Path.GetFullPath path)) <| fun () ->
  810. showTest path
  811. Assert.Equal("", true, true)
  812. )
  813. else [||]
  814. testList mockTestList tests
  815. [<EntryPoint;System.STAThread>]
  816. let main args =
  817. let isFullTest () =
  818. let rec whileYOrN () =
  819. match System.Console.ReadKey().Key with
  820. | System.ConsoleKey.Y -> true
  821. | System.ConsoleKey.N -> false
  822. | x ->
  823. printfn "`y` or `n` but %A" x
  824. whileYOrN ()
  825. printfn "Full test? (`y` or `n`)"
  826. whileYOrN ()
  827. let f isFullTest =
  828. if isFullTest then
  829. defaultMainThisAssembly args
  830. else
  831. defaultMainThisAssemblyFilter args
  832. (fun x ->
  833. x.Where(fun x -> not <| x.StartsWith TestOnMocks.mockTestList))
  834. match args with
  835. | [|"--full"|] -> f true
  836. | [||] ->
  837. f (isFullTest ())
  838. | _ ->
  839. printfn "`--full` or pass args but: %A" args
  840. 1