diff options
140 files changed, 9871 insertions, 3383 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index 89bd643..f0d67a5 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md | |||
@@ -16,19 +16,29 @@ Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. | |||
16 | ### An Overview of YueScript | 16 | ### An Overview of YueScript |
17 | ```moonscript | 17 | ```moonscript |
18 | -- import syntax | 18 | -- import syntax |
19 | import "yue" as :p, :to_lua | 19 | import p, to_lua from "yue" |
20 | 20 | ||
21 | -- object literals | 21 | -- object literals |
22 | inventory = | 22 | inventory = |
23 | equipment: | 23 | equipment: |
24 | * "sword" | 24 | - "sword" |
25 | * "shield" | 25 | - "shield" |
26 | items: | 26 | items: |
27 | * name: "potion" | 27 | - name: "potion" |
28 | count: 10 | 28 | count: 10 |
29 | * name: "bread" | 29 | - name: "bread" |
30 | count: 3 | 30 | count: 3 |
31 | 31 | ||
32 | -- list comprehension | ||
33 | map = (arr, action) -> | ||
34 | [action item for item in *arr] | ||
35 | |||
36 | filter = (arr, cond) -> | ||
37 | [item for item in *arr when cond item] | ||
38 | |||
39 | reduce = (arr, init, action): init -> | ||
40 | init = action init, item for item in *arr | ||
41 | |||
32 | -- pipe operator | 42 | -- pipe operator |
33 | [1, 2, 3] | 43 | [1, 2, 3] |
34 | |> map (x) -> x * 2 | 44 | |> map (x) -> x * 2 |
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本" | |||
51 | <YueDisplay> | 61 | <YueDisplay> |
52 | <pre> | 62 | <pre> |
53 | -- import syntax | 63 | -- import syntax |
54 | import "yue" as :p, :to_lua | 64 | import p, to_lua from "yue" |
55 | 65 | ||
56 | -- object literals | 66 | -- object literals |
57 | inventory = | 67 | inventory = |
58 | equipment: | 68 | equipment: |
59 | * "sword" | 69 | - "sword" |
60 | * "shield" | 70 | - "shield" |
61 | items: | 71 | items: |
62 | * name: "potion" | 72 | - name: "potion" |
63 | count: 10 | 73 | count: 10 |
64 | * name: "bread" | 74 | - name: "bread" |
65 | count: 3 | 75 | count: 3 |
66 | 76 | ||
77 | -- list comprehension | ||
78 | map = (arr, action) -> | ||
79 | [action item for item in *arr] | ||
80 | |||
81 | filter = (arr, cond) -> | ||
82 | [item for item in *arr when cond item] | ||
83 | |||
84 | reduce = (arr, init, action): init -> | ||
85 | init = action init, item for item in *arr | ||
86 | |||
67 | -- pipe operator | 87 | -- pipe operator |
68 | [1, 2, 3] | 88 | [1, 2, 3] |
69 | |> map (x) -> x * 2 | 89 | |> map (x) -> x * 2 |
@@ -132,14 +152,14 @@ export 🌛 = "月之脚本" | |||
132 | 152 | ||
133 |  Use YueScript module in Lua: | 153 |  Use YueScript module in Lua: |
134 | 154 | ||
135 | * **Case 1** | 155 | * **Case 1** |
136 | Require "your_yuescript_entry.yue" in Lua. | 156 | Require "your_yuescript_entry.yue" in Lua. |
137 | ```Lua | 157 | ```Lua |
138 | require("yue")("your_yuescript_entry") | 158 | require("yue")("your_yuescript_entry") |
139 | ``` | 159 | ``` |
140 |  And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly. | 160 |  And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly. |
141 | 161 | ||
142 | * **Case 2** | 162 | * **Case 2** |
143 | Require YueScript module and rewite message by hand. | 163 | Require YueScript module and rewite message by hand. |
144 | ```lua | 164 | ```lua |
145 | local yue = require("yue") | 165 | local yue = require("yue") |
@@ -151,7 +171,7 @@ end, function(err) | |||
151 | end) | 171 | end) |
152 | ``` | 172 | ``` |
153 | 173 | ||
154 | * **Case 3** | 174 | * **Case 3** |
155 | Use the YueScript compiler function in Lua. | 175 | Use the YueScript compiler function in Lua. |
156 | ```lua | 176 | ```lua |
157 | local yue = require("yue") | 177 | local yue = require("yue") |
@@ -203,12 +223,12 @@ Usage: yue [options|files|directories] ... | |||
203 | Execute without options to enter REPL, type symbol '$' | 223 | Execute without options to enter REPL, type symbol '$' |
204 | in a single line to start/stop multi-line mode | 224 | in a single line to start/stop multi-line mode |
205 | ``` | 225 | ``` |
206 |   Use cases: | 226 |   Use cases: |
207 |   Recursively compile every YueScript file with extension **.yue** under current path: **yue .** | 227 |   Recursively compile every YueScript file with extension **.yue** under current path: **yue .** |
208 |   Compile and save results to a target path: **yue -t /target/path/ .** | 228 |   Compile and save results to a target path: **yue -t /target/path/ .** |
209 |   Compile and reserve debug info: **yue -l .** | 229 |   Compile and reserve debug info: **yue -l .** |
210 |   Compile and generate minified codes: **yue -m .** | 230 |   Compile and generate minified codes: **yue -m .** |
211 |   Execute raw codes: **yue -e 'print 123'** | 231 |   Execute raw codes: **yue -e 'print 123'** |
212 |   Execute a YueScript file: **yue -e main.yue** | 232 |   Execute a YueScript file: **yue -e main.yue** |
213 | 233 | ||
214 | ## Macro | 234 | ## Macro |
@@ -424,6 +444,54 @@ print "Valid enum type:", $BodyType Static | |||
424 | </pre> | 444 | </pre> |
425 | </YueDisplay> | 445 | </YueDisplay> |
426 | 446 | ||
447 | ### Argument Validation | ||
448 | |||
449 | You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time. | ||
450 | |||
451 | ```moonscript | ||
452 | macro printNumAndStr = (num `Num, str `String) -> | | ||
453 | print( | ||
454 | #{num} | ||
455 | #{str} | ||
456 | ) | ||
457 | |||
458 | $printNumAndStr 123, "hello" | ||
459 | ``` | ||
460 | <YueDisplay> | ||
461 | <pre> | ||
462 | macro printNumAndStr = (num `Num, str `String) -> | | ||
463 | print( | ||
464 | #{num} | ||
465 | #{str} | ||
466 | ) | ||
467 | |||
468 | $printNumAndStr 123, "hello" | ||
469 | </pre> | ||
470 | </YueDisplay> | ||
471 | |||
472 | If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place. | ||
473 | |||
474 | ```moonscript | ||
475 | macro printNumAndStr = (num, str) -> | ||
476 | error "expected Num as first argument" unless $is_ast Num, num | ||
477 | error "expected String as second argument" unless $is_ast String, str | ||
478 | "print(#{num}, #{str})" | ||
479 | |||
480 | $printNumAndStr 123, "hello" | ||
481 | ``` | ||
482 | <YueDisplay> | ||
483 | <pre> | ||
484 | macro printNumAndStr = (num, str) -> | ||
485 | error "expected Num as first argument" unless $is_ast Num, num | ||
486 | error "expected String as second argument" unless $is_ast String, str | ||
487 | "print(#{num}, #{str})" | ||
488 | |||
489 | $printNumAndStr 123, "hello" | ||
490 | </pre> | ||
491 | </YueDisplay> | ||
492 | |||
493 | For more details about available AST nodes, please refer to the uppercased definitions in [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp). | ||
494 | |||
427 | ## Operator | 495 | ## Operator |
428 | 496 | ||
429 | All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes. | 497 | All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes. |
@@ -566,11 +634,26 @@ merge = {...a, ...b} | |||
566 | </pre> | 634 | </pre> |
567 | </YueDisplay> | 635 | </YueDisplay> |
568 | 636 | ||
637 | ### Table Reversed Indexing | ||
638 | |||
639 | You can use the **#** operator to get the last elements of a table. | ||
640 | |||
641 | ```moonscript | ||
642 | last = data.items[#] | ||
643 | second_last = data.items[#-1] | ||
644 | ``` | ||
645 | <YueDisplay> | ||
646 | <pre> | ||
647 | last = data.items[#] | ||
648 | second_last = data.items[#-1] | ||
649 | </pre> | ||
650 | </YueDisplay> | ||
651 | |||
569 | ### Metatable | 652 | ### Metatable |
570 | 653 | ||
571 | The **<>** operator can be used as a shortcut for metatable manipulation. | 654 | The **<>** operator can be used as a shortcut for metatable manipulation. |
572 | 655 | ||
573 | * **Metatable Creation** | 656 | * **Metatable Creation** |
574 | Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. | 657 | Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. |
575 | 658 | ||
576 | ```moonscript | 659 | ```moonscript |
@@ -606,7 +689,7 @@ close _ = <close>: -> print "out of scope" | |||
606 | </pre> | 689 | </pre> |
607 | </YueDisplay> | 690 | </YueDisplay> |
608 | 691 | ||
609 | * **Metatable Accessing** | 692 | * **Metatable Accessing** |
610 | Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. | 693 | Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. |
611 | 694 | ||
612 | ```moonscript | 695 | ```moonscript |
@@ -630,7 +713,7 @@ print tb.item | |||
630 | </pre> | 713 | </pre> |
631 | </YueDisplay> | 714 | </YueDisplay> |
632 | 715 | ||
633 | * **Metatable Destructure** | 716 | * **Metatable Destructure** |
634 | Destruct metatable with metamethod key surrounded by **<>**. | 717 | Destruct metatable with metamethod key surrounded by **<>**. |
635 | 718 | ||
636 | ```moonscript | 719 | ```moonscript |
@@ -732,34 +815,45 @@ a ??= false | |||
732 | 815 | ||
733 | ### Implicit Object | 816 | ### Implicit Object |
734 | 817 | ||
735 | You can write a list of implicit structures that starts with the symbol **\*** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent. | 818 | You can write a list of implicit structures that starts with the symbol **\*** or **-** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent. |
819 | |||
736 | ```moonscript | 820 | ```moonscript |
821 | -- assignment with implicit object | ||
737 | list = | 822 | list = |
738 | * 1 | 823 | * 1 |
739 | * 2 | 824 | * 2 |
740 | * 3 | 825 | * 3 |
741 | 826 | ||
827 | -- function call with implicit object | ||
742 | func | 828 | func |
743 | * 1 | 829 | * 1 |
744 | * 2 | 830 | * 2 |
745 | * 3 | 831 | * 3 |
746 | 832 | ||
833 | -- return with implicit object | ||
834 | f = -> | ||
835 | return | ||
836 | * 1 | ||
837 | * 2 | ||
838 | * 3 | ||
839 | |||
840 | -- table with implicit object | ||
747 | tb = | 841 | tb = |
748 | name: "abc" | 842 | name: "abc" |
749 | 843 | ||
750 | values: | 844 | values: |
751 | * "a" | 845 | - "a" |
752 | * "b" | 846 | - "b" |
753 | * "c" | 847 | - "c" |
754 | 848 | ||
755 | objects: | 849 | objects: |
756 | * name: "a" | 850 | - name: "a" |
757 | value: 1 | 851 | value: 1 |
758 | func: => @value + 1 | 852 | func: => @value + 1 |
759 | tb: | 853 | tb: |
760 | fieldA: 1 | 854 | fieldA: 1 |
761 | 855 | ||
762 | * name: "b" | 856 | - name: "b" |
763 | value: 2 | 857 | value: 2 |
764 | func: => @value + 2 | 858 | func: => @value + 2 |
765 | tb: { } | 859 | tb: { } |
@@ -767,32 +861,42 @@ tb = | |||
767 | ``` | 861 | ``` |
768 | <YueDisplay> | 862 | <YueDisplay> |
769 | <pre> | 863 | <pre> |
864 | -- assignment with implicit object | ||
770 | list = | 865 | list = |
771 | * 1 | 866 | * 1 |
772 | * 2 | 867 | * 2 |
773 | * 3 | 868 | * 3 |
774 | 869 | ||
870 | -- function call with implicit object | ||
775 | func | 871 | func |
776 | * 1 | 872 | * 1 |
777 | * 2 | 873 | * 2 |
778 | * 3 | 874 | * 3 |
779 | 875 | ||
876 | -- return with implicit object | ||
877 | f = -> | ||
878 | return | ||
879 | * 1 | ||
880 | * 2 | ||
881 | * 3 | ||
882 | |||
883 | -- table with implicit object | ||
780 | tb = | 884 | tb = |
781 | name: "abc" | 885 | name: "abc" |
782 | 886 | ||
783 | values: | 887 | values: |
784 | * "a" | 888 | - "a" |
785 | * "b" | 889 | - "b" |
786 | * "c" | 890 | - "c" |
787 | 891 | ||
788 | objects: | 892 | objects: |
789 | * name: "a" | 893 | - name: "a" |
790 | value: 1 | 894 | value: 1 |
791 | func: => @value + 1 | 895 | func: => @value + 1 |
792 | tb: | 896 | tb: |
793 | fieldA: 1 | 897 | fieldA: 1 |
794 | 898 | ||
795 | * name: "b" | 899 | - name: "b" |
796 | value: 2 | 900 | value: 2 |
797 | func: => @value + 2 | 901 | func: => @value + 2 |
798 | tb: { } | 902 | tb: { } |
@@ -860,7 +964,7 @@ do | |||
860 | 964 | ||
861 | The export statement offers a concise way to define modules. | 965 | The export statement offers a concise way to define modules. |
862 | 966 | ||
863 | * **Named Export** | 967 | * **Named Export** |
864 | Named export will define a local variable as well as adding a field in the exported table. | 968 | Named export will define a local variable as well as adding a field in the exported table. |
865 | 969 | ||
866 | ```moonscript | 970 | ```moonscript |
@@ -924,7 +1028,7 @@ export["a-b-c"] = 123 | |||
924 | </pre> | 1028 | </pre> |
925 | </YueDisplay> | 1029 | </YueDisplay> |
926 | 1030 | ||
927 | * **Unnamed Export** | 1031 | * **Unnamed Export** |
928 | Unnamed export will add the target item into the array part of the exported table. | 1032 | Unnamed export will add the target item into the array part of the exported table. |
929 | 1033 | ||
930 | ```moonscript | 1034 | ```moonscript |
@@ -954,7 +1058,7 @@ export with tmp | |||
954 | </pre> | 1058 | </pre> |
955 | </YueDisplay> | 1059 | </YueDisplay> |
956 | 1060 | ||
957 | * **Default Export** | 1061 | * **Default Export** |
958 | Using the **default** keyword in export statement to replace the exported table with any thing. | 1062 | Using the **default** keyword in export statement to replace the exported table with any thing. |
959 | 1063 | ||
960 | ```moonscript | 1064 | ```moonscript |
@@ -1202,7 +1306,7 @@ If the destructuring statement is complicated, feel free to spread it out over a | |||
1202 | </pre> | 1306 | </pre> |
1203 | </YueDisplay> | 1307 | </YueDisplay> |
1204 | 1308 | ||
1205 | It’s common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: | 1309 | It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: |
1206 | 1310 | ||
1207 | ```moonscript | 1311 | ```moonscript |
1208 | {:concat, :insert} = table | 1312 | {:concat, :insert} = table |
@@ -1246,6 +1350,52 @@ You can use `_` as placeholder when doing a list destructuring: | |||
1246 | </pre> | 1350 | </pre> |
1247 | </YueDisplay> | 1351 | </YueDisplay> |
1248 | 1352 | ||
1353 | ### Range Destructuring | ||
1354 | |||
1355 | You can use the spread operator `...` in list destructuring to capture a range of values. This is useful when you want to extract specific elements from the beginning and end of a list while collecting the rest in between. | ||
1356 | |||
1357 | ```moonscript | ||
1358 | orders = ["first", "second", "third", "fourth", "last"] | ||
1359 | [first, ...bulk, last] = orders | ||
1360 | print first -- prints: first | ||
1361 | print bulk -- prints: {"second", "third", "fourth"} | ||
1362 | print last -- prints: last | ||
1363 | ``` | ||
1364 | <YueDisplay> | ||
1365 | <pre> | ||
1366 | orders = ["first", "second", "third", "fourth", "last"] | ||
1367 | [first, ...bulk, last] = orders | ||
1368 | print first -- prints: first | ||
1369 | print bulk -- prints: {"second", "third", "fourth"} | ||
1370 | print last -- prints: last | ||
1371 | </pre> | ||
1372 | </YueDisplay> | ||
1373 | |||
1374 | The spread operator can be used in different positions to capture different ranges, and you can use `_` as a placeholder for the values you don't want to capture: | ||
1375 | |||
1376 | ```moonscript | ||
1377 | -- Capture everything after first element | ||
1378 | [first, ...rest] = orders | ||
1379 | |||
1380 | -- Capture everything before last element | ||
1381 | [...start, last] = orders | ||
1382 | |||
1383 | -- Capture things except the middle elements | ||
1384 | [first, ..._, last] = orders | ||
1385 | ``` | ||
1386 | <YueDisplay> | ||
1387 | <pre> | ||
1388 | -- Capture everything after first element | ||
1389 | [first, ...rest] = orders | ||
1390 | |||
1391 | -- Capture everything before last element | ||
1392 | [...start, last] = orders | ||
1393 | |||
1394 | -- Capture things except the middle elements | ||
1395 | [first, ..._, last] = orders | ||
1396 | </pre> | ||
1397 | </YueDisplay> | ||
1398 | |||
1249 | ### Destructuring In Other Places | 1399 | ### Destructuring In Other Places |
1250 | 1400 | ||
1251 | Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: | 1401 | Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: |
@@ -1475,6 +1625,47 @@ catch err | |||
1475 | </pre> | 1625 | </pre> |
1476 | </YueDisplay> | 1626 | </YueDisplay> |
1477 | 1627 | ||
1628 | ### Try? | ||
1629 | |||
1630 | `try?` is a simplified use for error handling syntax that omit the boolean status from the `try` statement, and it will return the result from the try block when success, return nil instead of error object otherwise. | ||
1631 | |||
1632 | ```moonscript | ||
1633 | a, b, c = try? func! | ||
1634 | |||
1635 | -- with nil coalescing operator | ||
1636 | a = (try? func!) ?? "default" | ||
1637 | |||
1638 | -- as function argument | ||
1639 | f try? func! | ||
1640 | |||
1641 | -- with catch block | ||
1642 | f try? | ||
1643 | print 123 | ||
1644 | func! | ||
1645 | catch e | ||
1646 | print e | ||
1647 | e | ||
1648 | ``` | ||
1649 | <YueDisplay> | ||
1650 | <pre> | ||
1651 | a, b, c = try? func! | ||
1652 | |||
1653 | -- with nil coalescing operator | ||
1654 | a = (try? func!) ?? "default" | ||
1655 | |||
1656 | -- as function argument | ||
1657 | f try? func! | ||
1658 | |||
1659 | -- with catch block | ||
1660 | f try? | ||
1661 | print 123 | ||
1662 | func! | ||
1663 | catch e | ||
1664 | print e | ||
1665 | e | ||
1666 | </pre> | ||
1667 | </YueDisplay> | ||
1668 | |||
1478 | ## Attributes | 1669 | ## Attributes |
1479 | 1670 | ||
1480 | Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4. | 1671 | Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4. |
@@ -1503,6 +1694,19 @@ const {:a, :b, c, d} = tb | |||
1503 | </pre> | 1694 | </pre> |
1504 | </YueDisplay> | 1695 | </YueDisplay> |
1505 | 1696 | ||
1697 | You can also declare a global variable to be `const`. | ||
1698 | |||
1699 | ```moonscript | ||
1700 | global const Constant = 123 | ||
1701 | -- Constant = 1 | ||
1702 | ``` | ||
1703 | <YueDisplay> | ||
1704 | <pre> | ||
1705 | global const Constant = 123 | ||
1706 | -- Constant = 1 | ||
1707 | </pre> | ||
1708 | </YueDisplay> | ||
1709 | |||
1506 | ## Literals | 1710 | ## Literals |
1507 | 1711 | ||
1508 | All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. | 1712 | All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. |
@@ -1535,12 +1739,73 @@ You can use underscores in a number literal to increase readability. | |||
1535 | ```moonscript | 1739 | ```moonscript |
1536 | integer = 1_000_000 | 1740 | integer = 1_000_000 |
1537 | hex = 0xEF_BB_BF | 1741 | hex = 0xEF_BB_BF |
1742 | binary = 0B10011 | ||
1538 | ``` | 1743 | ``` |
1539 | <YueDisplay> | 1744 | <YueDisplay> |
1540 | 1745 | ||
1541 | <pre> | 1746 | <pre> |
1542 | integer = 1_000_000 | 1747 | integer = 1_000_000 |
1543 | hex = 0xEF_BB_BF | 1748 | hex = 0xEF_BB_BF |
1749 | binary = 0B10011 | ||
1750 | </pre> | ||
1751 | </YueDisplay> | ||
1752 | |||
1753 | ### YAML Multiline String | ||
1754 | |||
1755 | The `|` prefix introduces a YAML-style multiline string literal: | ||
1756 | |||
1757 | ```moonscript | ||
1758 | str = | | ||
1759 | key: value | ||
1760 | list: | ||
1761 | - item1 | ||
1762 | - #{expr} | ||
1763 | ``` | ||
1764 | <YueDisplay> | ||
1765 | <pre> | ||
1766 | str = | | ||
1767 | key: value | ||
1768 | list: | ||
1769 | - item1 | ||
1770 | - #{expr} | ||
1771 | </pre> | ||
1772 | </YueDisplay> | ||
1773 | |||
1774 | This allows writing structured multiline text conveniently. All line breaks and indentation are preserved relative to the first non-empty line, and expressions inside `#{...}` are interpolated automatically as `tostring(expr)`. | ||
1775 | |||
1776 | YAML Multiline String automatically detects the common leading whitespace prefix (minimum indentation across all non-empty lines) and removes it from all lines. This makes it easy to indent your code visually without affecting the resulting string content. | ||
1777 | |||
1778 | ```moonscript | ||
1779 | fn = -> | ||
1780 | str = | | ||
1781 | foo: | ||
1782 | bar: baz | ||
1783 | return str | ||
1784 | ``` | ||
1785 | <YueDisplay> | ||
1786 | <pre> | ||
1787 | fn = -> | ||
1788 | str = | | ||
1789 | foo: | ||
1790 | bar: baz | ||
1791 | return str | ||
1792 | </pre> | ||
1793 | </YueDisplay> | ||
1794 | |||
1795 | Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures. | ||
1796 | |||
1797 | All special characters like quotes (`"`) and backslashes (`\`) in the YAMLMultiline block are automatically escaped so that the generated Lua string is syntactically valid and behaves as expected. | ||
1798 | |||
1799 | ```moonscript | ||
1800 | str = | | ||
1801 | path: "C:\Program Files\App" | ||
1802 | note: 'He said: "#{Hello}!"' | ||
1803 | ``` | ||
1804 | <YueDisplay> | ||
1805 | <pre> | ||
1806 | str = | | ||
1807 | path: "C:\Program Files\App" | ||
1808 | note: 'He said: "#{Hello}!"' | ||
1544 | </pre> | 1809 | </pre> |
1545 | </YueDisplay> | 1810 | </YueDisplay> |
1546 | 1811 | ||
@@ -1902,22 +2167,22 @@ x * 2 | |||
1902 | </pre> | 2167 | </pre> |
1903 | </YueDisplay> | 2168 | </YueDisplay> |
1904 | 2169 | ||
1905 | If you wish to have further code after your backcalls, you can set them aside with a do statement. | 2170 | If you wish to have further code after your backcalls, you can set them aside with a do statement. And the parentheses can be omitted with non-fat arrow functions. |
1906 | 2171 | ||
1907 | ```moonscript | 2172 | ```moonscript |
1908 | result, msg = do | 2173 | result, msg = do |
1909 | (data) <- readAsync "filename.txt" | 2174 | data <- readAsync "filename.txt" |
1910 | print data | 2175 | print data |
1911 | (info) <- processAsync data | 2176 | info <- processAsync data |
1912 | check info | 2177 | check info |
1913 | print result, msg | 2178 | print result, msg |
1914 | ``` | 2179 | ``` |
1915 | <YueDisplay> | 2180 | <YueDisplay> |
1916 | <pre> | 2181 | <pre> |
1917 | result, msg = do | 2182 | result, msg = do |
1918 | (data) <- readAsync "filename.txt" | 2183 | data <- readAsync "filename.txt" |
1919 | print data | 2184 | print data |
1920 | (info) <- processAsync data | 2185 | info <- processAsync data |
1921 | check info | 2186 | check info |
1922 | print result, msg | 2187 | print result, msg |
1923 | </pre> | 2188 | </pre> |
@@ -2096,13 +2361,11 @@ doubled = [item * 2 for i, item in ipairs items] | |||
2096 | The items included in the new table can be restricted with a when clause: | 2361 | The items included in the new table can be restricted with a when clause: |
2097 | 2362 | ||
2098 | ```moonscript | 2363 | ```moonscript |
2099 | iter = ipairs items | 2364 | slice = [item for i, item in ipairs items when i > 1 and i < 3] |
2100 | slice = [item for i, item in iter when i > 1 and i < 3] | ||
2101 | ``` | 2365 | ``` |
2102 | <YueDisplay> | 2366 | <YueDisplay> |
2103 | <pre> | 2367 | <pre> |
2104 | iter = ipairs items | 2368 | slice = [item for i, item in ipairs items when i > 1 and i < 3] |
2105 | slice = [item for i, item in iter when i > 1 and i < 3] | ||
2106 | </pre> | 2369 | </pre> |
2107 | </YueDisplay> | 2370 | </YueDisplay> |
2108 | 2371 | ||
@@ -2250,6 +2513,45 @@ slice = [item for item in *items[,,2]] | |||
2250 | </pre> | 2513 | </pre> |
2251 | </YueDisplay> | 2514 | </YueDisplay> |
2252 | 2515 | ||
2516 | Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table. | ||
2517 | |||
2518 | ```moonscript | ||
2519 | -- take the last 4 items | ||
2520 | slice = [item for item in *items[-4,-1]] | ||
2521 | ``` | ||
2522 | <YueDisplay> | ||
2523 | <pre> | ||
2524 | -- take the last 4 items | ||
2525 | slice = [item for item in *items[-4,-1]] | ||
2526 | </pre> | ||
2527 | </YueDisplay> | ||
2528 | |||
2529 | The step size can also be negative, which means that the items are taken in reverse order. | ||
2530 | |||
2531 | ```moonscript | ||
2532 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
2533 | ``` | ||
2534 | <YueDisplay> | ||
2535 | <pre> | ||
2536 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
2537 | </pre> | ||
2538 | </YueDisplay> | ||
2539 | |||
2540 | #### Slicing Expression | ||
2541 | |||
2542 | Slicing can also be used as an expression. This is useful for getting a sub-list of a table. | ||
2543 | |||
2544 | ```moonscript | ||
2545 | -- take the 2nd and 4th items as a new list | ||
2546 | sub_list = items[2, 4] | ||
2547 | ``` | ||
2548 | <YueDisplay> | ||
2549 | <pre> | ||
2550 | -- take the 2nd and 4th items as a new list | ||
2551 | sub_list = items[2, 4] | ||
2552 | </pre> | ||
2553 | </YueDisplay> | ||
2554 | |||
2253 | ## For Loop | 2555 | ## For Loop |
2254 | 2556 | ||
2255 | There are two for loop forms, just like in Lua. A numeric one and a generic one: | 2557 | There are two for loop forms, just like in Lua. A numeric one and a generic one: |
@@ -2326,6 +2628,23 @@ doubled_evens = for i = 1, 20 | |||
2326 | </pre> | 2628 | </pre> |
2327 | </YueDisplay> | 2629 | </YueDisplay> |
2328 | 2630 | ||
2631 | In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result. | ||
2632 | |||
2633 | For example, to find the first number greater than 10: | ||
2634 | |||
2635 | ```moonscript | ||
2636 | first_large = for n in *numbers | ||
2637 | break n if n > 10 | ||
2638 | ``` | ||
2639 | <YueDisplay> | ||
2640 | <pre> | ||
2641 | first_large = for n in *numbers | ||
2642 | break n if n > 10 | ||
2643 | </pre> | ||
2644 | </YueDisplay> | ||
2645 | |||
2646 | This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions. | ||
2647 | |||
2329 | You can also filter values by combining the for loop expression with the continue statement. | 2648 | You can also filter values by combining the for loop expression with the continue statement. |
2330 | 2649 | ||
2331 | For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. | 2650 | For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. |
@@ -2347,7 +2666,7 @@ print func_b! -- prints table object | |||
2347 | </pre> | 2666 | </pre> |
2348 | </YueDisplay> | 2667 | </YueDisplay> |
2349 | 2668 | ||
2350 | This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop. | 2669 | This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop. |
2351 | 2670 | ||
2352 | ## Repeat Loop | 2671 | ## Repeat Loop |
2353 | 2672 | ||
@@ -2626,28 +2945,26 @@ reader\parse_line! until reader\eof! | |||
2626 | 2945 | ||
2627 | ## Switch | 2946 | ## Switch |
2628 | 2947 | ||
2629 | The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. | 2948 | The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. In switch statement, you can also use assignment expression to store temporary variable value. |
2630 | 2949 | ||
2631 | ```moonscript | 2950 | ```moonscript |
2632 | name = "Dan" | 2951 | switch name := "Dan" |
2633 | switch name | ||
2634 | when "Robert" | 2952 | when "Robert" |
2635 | print "You are Robert" | 2953 | print "You are Robert" |
2636 | when "Dan", "Daniel" | 2954 | when "Dan", "Daniel" |
2637 | print "Your name, it's Dan" | 2955 | print "Your name, it's Dan" |
2638 | else | 2956 | else |
2639 | print "I don't know about your name" | 2957 | print "I don't know about you with name #{name}" |
2640 | ``` | 2958 | ``` |
2641 | <YueDisplay> | 2959 | <YueDisplay> |
2642 | <pre> | 2960 | <pre> |
2643 | name = "Dan" | 2961 | switch name := "Dan" |
2644 | switch name | ||
2645 | when "Robert" | 2962 | when "Robert" |
2646 | print "You are Robert" | 2963 | print "You are Robert" |
2647 | when "Dan", "Daniel" | 2964 | when "Dan", "Daniel" |
2648 | print "Your name, it's Dan" | 2965 | print "Your name, it's Dan" |
2649 | else | 2966 | else |
2650 | print "I don't know about your name" | 2967 | print "I don't know about you with name #{name}" |
2651 | </pre> | 2968 | </pre> |
2652 | </YueDisplay> | 2969 | </YueDisplay> |
2653 | 2970 | ||
@@ -2678,7 +2995,7 @@ next_number = switch b | |||
2678 | </pre> | 2995 | </pre> |
2679 | </YueDisplay> | 2996 | </YueDisplay> |
2680 | 2997 | ||
2681 | We can use the then keyword to write a switch’s when block on a single line. No extra keyword is needed to write the else block on a single line. | 2998 | We can use the then keyword to write a switch's when block on a single line. No extra keyword is needed to write the else block on a single line. |
2682 | 2999 | ||
2683 | ```moonscript | 3000 | ```moonscript |
2684 | msg = switch math.random(1, 5) | 3001 | msg = switch math.random(1, 5) |
@@ -2724,7 +3041,7 @@ else | |||
2724 | </pre> | 3041 | </pre> |
2725 | </YueDisplay> | 3042 | </YueDisplay> |
2726 | 3043 | ||
2727 | It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod. | 3044 | It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's expression wants to overwrite how the comparison is done by defining an eq metamethod. |
2728 | 3045 | ||
2729 | ### Table Matching | 3046 | ### Table Matching |
2730 | 3047 | ||
@@ -2784,6 +3101,123 @@ switch item | |||
2784 | </pre> | 3101 | </pre> |
2785 | </YueDisplay> | 3102 | </YueDisplay> |
2786 | 3103 | ||
3104 | You can also match against array elements, table fields, and even nested structures with array or table literals. | ||
3105 | |||
3106 | Match against array elements. | ||
3107 | |||
3108 | ```moonscript | ||
3109 | switch tb | ||
3110 | when [1, 2, 3] | ||
3111 | print "1, 2, 3" | ||
3112 | when [1, b, 3] | ||
3113 | print "1, #{b}, 3" | ||
3114 | when [1, 2, b = 3] -- b has a default value | ||
3115 | print "1, 2, #{b}" | ||
3116 | ``` | ||
3117 | <YueDisplay> | ||
3118 | <pre> | ||
3119 | switch tb | ||
3120 | when [1, 2, 3] | ||
3121 | print "1, 2, 3" | ||
3122 | when [1, b, 3] | ||
3123 | print "1, #{b}, 3" | ||
3124 | when [1, 2, b = 3] -- b has a default value | ||
3125 | print "1, 2, #{b}" | ||
3126 | </pre> | ||
3127 | </YueDisplay> | ||
3128 | |||
3129 | Match against table fields with destructuring. | ||
3130 | |||
3131 | ```moonscript | ||
3132 | switch tb | ||
3133 | when success: true, :result | ||
3134 | print "success", result | ||
3135 | when success: false | ||
3136 | print "failed", result | ||
3137 | else | ||
3138 | print "invalid" | ||
3139 | ``` | ||
3140 | <YueDisplay> | ||
3141 | <pre> | ||
3142 | switch tb | ||
3143 | when success: true, :result | ||
3144 | print "success", result | ||
3145 | when success: false | ||
3146 | print "failed", result | ||
3147 | else | ||
3148 | print "invalid" | ||
3149 | </pre> | ||
3150 | </YueDisplay> | ||
3151 | |||
3152 | Match against nested table structures. | ||
3153 | |||
3154 | ```moonscript | ||
3155 | switch tb | ||
3156 | when data: {type: "success", :content} | ||
3157 | print "success", content | ||
3158 | when data: {type: "error", :content} | ||
3159 | print "failed", content | ||
3160 | else | ||
3161 | print "invalid" | ||
3162 | ``` | ||
3163 | <YueDisplay> | ||
3164 | <pre> | ||
3165 | switch tb | ||
3166 | when data: {type: "success", :content} | ||
3167 | print "success", content | ||
3168 | when data: {type: "error", :content} | ||
3169 | print "failed", content | ||
3170 | else | ||
3171 | print "invalid" | ||
3172 | </pre> | ||
3173 | </YueDisplay> | ||
3174 | |||
3175 | Match against array of tables. | ||
3176 | |||
3177 | ```moonscript | ||
3178 | switch tb | ||
3179 | when [ | ||
3180 | {a: 1, b: 2} | ||
3181 | {a: 3, b: 4} | ||
3182 | {a: 5, b: 6} | ||
3183 | fourth | ||
3184 | ] | ||
3185 | print "matched", fourth | ||
3186 | ``` | ||
3187 | <YueDisplay> | ||
3188 | <pre> | ||
3189 | switch tb | ||
3190 | when [ | ||
3191 | {a: 1, b: 2} | ||
3192 | {a: 3, b: 4} | ||
3193 | {a: 5, b: 6} | ||
3194 | fourth | ||
3195 | ] | ||
3196 | print "matched", fourth | ||
3197 | </pre> | ||
3198 | </YueDisplay> | ||
3199 | |||
3200 | Match against a list and capture a range of elements. | ||
3201 | |||
3202 | ```moonscript | ||
3203 | segments = ["admin", "users", "logs", "view"] | ||
3204 | switch segments | ||
3205 | when [...groups, resource, action] | ||
3206 | print "Group:", groups -- prints: {"admin", "users"} | ||
3207 | print "Resource:", resource -- prints: "logs" | ||
3208 | print "Action:", action -- prints: "view" | ||
3209 | ``` | ||
3210 | <YueDisplay> | ||
3211 | <pre> | ||
3212 | segments = ["admin", "users", "logs", "view"] | ||
3213 | switch segments | ||
3214 | when [...groups, resource, action] | ||
3215 | print "Group:", groups -- prints: {"admin", "users"} | ||
3216 | print "Resource:", resource -- prints: "logs" | ||
3217 | print "Action:", action -- prints: "view" | ||
3218 | </pre> | ||
3219 | </YueDisplay> | ||
3220 | |||
2787 | ## Object Oriented Programming | 3221 | ## Object Oriented Programming |
2788 | 3222 | ||
2789 | In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details. | 3223 | In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details. |
@@ -2915,7 +3349,7 @@ class BackPack extends Inventory | |||
2915 | 3349 | ||
2916 | Here we extend our Inventory class, and limit the amount of items it can carry. | 3350 | Here we extend our Inventory class, and limit the amount of items it can carry. |
2917 | 3351 | ||
2918 | In this example, we don’t define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. | 3352 | In this example, we don't define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. |
2919 | 3353 | ||
2920 | Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. | 3354 | Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. |
2921 | 3355 | ||
@@ -3002,13 +3436,13 @@ print BackPack.size -- prints 10 | |||
3002 | 3436 | ||
3003 | The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class. | 3437 | The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class. |
3004 | 3438 | ||
3005 | The class object can be called like a function in order to create new instances. That’s how we created instances of classes in the examples above. | 3439 | The class object can be called like a function in order to create new instances. That's how we created instances of classes in the examples above. |
3006 | 3440 | ||
3007 | A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base. | 3441 | A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base. |
3008 | 3442 | ||
3009 | The class object’s metatable reads properties from the base if they don’t exist in the class object. This means we can access functions and properties directly from the class. | 3443 | The class object's metatable reads properties from the base if they don't exist in the class object. This means we can access functions and properties directly from the class. |
3010 | 3444 | ||
3011 | It is important to note that assigning to the class object does not assign into the base, so it’s not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. | 3445 | It is important to note that assigning to the class object does not assign into the base, so it's not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. |
3012 | 3446 | ||
3013 | The class object has a couple special properties: | 3447 | The class object has a couple special properties: |
3014 | 3448 | ||
@@ -3081,7 +3515,7 @@ print Counter.count -- prints 2 | |||
3081 | </pre> | 3515 | </pre> |
3082 | </YueDisplay> | 3516 | </YueDisplay> |
3083 | 3517 | ||
3084 | The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax. | 3518 | The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax. |
3085 | 3519 | ||
3086 | ```moonscript | 3520 | ```moonscript |
3087 | @@hello 1,2,3,4 | 3521 | @@hello 1,2,3,4 |
@@ -3096,7 +3530,7 @@ The calling semantics of @@ are similar to @. Calling a @@ name will pass the cl | |||
3096 | 3530 | ||
3097 | In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object. | 3531 | In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object. |
3098 | 3532 | ||
3099 | Here is an alternative way to create a class variable compared to what’s described above: | 3533 | Here is an alternative way to create a class variable compared to what's described above: |
3100 | 3534 | ||
3101 | ```moonscript | 3535 | ```moonscript |
3102 | class Things | 3536 | class Things |
@@ -3362,19 +3796,19 @@ In this usage, with can be seen as a special form of the K combinator. | |||
3362 | The expression in the with statement can also be an assignment, if you want to give a name to the expression. | 3796 | The expression in the with statement can also be an assignment, if you want to give a name to the expression. |
3363 | 3797 | ||
3364 | ```moonscript | 3798 | ```moonscript |
3365 | with str = "Hello" | 3799 | with str := "Hello" |
3366 | print "original:", str | 3800 | print "original:", str |
3367 | print "upper:", \upper! | 3801 | print "upper:", \upper! |
3368 | ``` | 3802 | ``` |
3369 | <YueDisplay> | 3803 | <YueDisplay> |
3370 | <pre> | 3804 | <pre> |
3371 | with str = "Hello" | 3805 | with str := "Hello" |
3372 | print "original:", str | 3806 | print "original:", str |
3373 | print "upper:", \upper! | 3807 | print "upper:", \upper! |
3374 | </pre> | 3808 | </pre> |
3375 | </YueDisplay> | 3809 | </YueDisplay> |
3376 | 3810 | ||
3377 | Accessing special keys with `[]` in a `with` statement. | 3811 | You can access special keys with `[]` in a `with` statement. |
3378 | 3812 | ||
3379 | ```moonscript | 3813 | ```moonscript |
3380 | with tb | 3814 | with tb |
@@ -3397,6 +3831,18 @@ with tb | |||
3397 | </pre> | 3831 | </pre> |
3398 | </YueDisplay> | 3832 | </YueDisplay> |
3399 | 3833 | ||
3834 | `with?` is an enhanced version of `with` syntax, which introduces an existential check to safely access objects that may be nil without explicit null checks. | ||
3835 | |||
3836 | ```moonscript | ||
3837 | with? obj | ||
3838 | print obj.name | ||
3839 | ``` | ||
3840 | <YueDisplay> | ||
3841 | <pre> | ||
3842 | with? obj | ||
3843 | print obj.name | ||
3844 | </pre> | ||
3845 | </YueDisplay> | ||
3400 | 3846 | ||
3401 | ## Do | 3847 | ## Do |
3402 | 3848 | ||
@@ -3417,7 +3863,7 @@ print var -- nil here | |||
3417 | </pre> | 3863 | </pre> |
3418 | </YueDisplay> | 3864 | </YueDisplay> |
3419 | 3865 | ||
3420 | YueScript’s **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. | 3866 | YueScript's **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. |
3421 | 3867 | ||
3422 | ```moonscript | 3868 | ```moonscript |
3423 | counter = do | 3869 | counter = do |
@@ -3543,7 +3989,7 @@ print i -- will print 0 | |||
3543 | </pre> | 3989 | </pre> |
3544 | </YueDisplay> | 3990 | </YueDisplay> |
3545 | 3991 | ||
3546 | In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn’t clear what names have already been declared. | 3992 | In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn't clear what names have already been declared. |
3547 | 3993 | ||
3548 | It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident. | 3994 | It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident. |
3549 | 3995 | ||
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 1a2da96..15f4768 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md | |||
@@ -16,19 +16,29 @@ Yueï¼ˆæœˆï¼‰æ˜¯ä¸æ–‡ä¸â€œæœˆäº®â€çš„å称。 | |||
16 | ### 月之脚本概览 | 16 | ### 月之脚本概览 |
17 | ```moonscript | 17 | ```moonscript |
18 | -- å¯¼å…¥è¯æ³• | 18 | -- å¯¼å…¥è¯æ³• |
19 | import "yue" as :p, :to_lua | 19 | import p, to_lua from "yue" |
20 | 20 | ||
21 | -- éšå¼å¯¹è±¡ | 21 | -- éšå¼å¯¹è±¡ |
22 | inventory = | 22 | inventory = |
23 | equipment: | 23 | equipment: |
24 | * "sword" | 24 | - "sword" |
25 | * "shield" | 25 | - "shield" |
26 | items: | 26 | items: |
27 | * name: "potion" | 27 | - name: "potion" |
28 | count: 10 | 28 | count: 10 |
29 | * name: "bread" | 29 | - name: "bread" |
30 | count: 3 | 30 | count: 3 |
31 | 31 | ||
32 | -- 列表推导 | ||
33 | map = (arr, action) -> | ||
34 | [action item for item in *arr] | ||
35 | |||
36 | filter = (arr, cond) -> | ||
37 | [item for item in *arr when cond item] | ||
38 | |||
39 | reduce = (arr, init, action): init -> | ||
40 | init = action init, item for item in *arr | ||
41 | |||
32 | -- ç®¡é“æ“作符 | 42 | -- ç®¡é“æ“作符 |
33 | [1, 2, 3] | 43 | [1, 2, 3] |
34 | |> map (x) -> x * 2 | 44 | |> map (x) -> x * 2 |
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本" | |||
51 | <YueDisplay> | 61 | <YueDisplay> |
52 | <pre> | 62 | <pre> |
53 | -- å¯¼å…¥è¯æ³• | 63 | -- å¯¼å…¥è¯æ³• |
54 | import "yue" as :p, :to_lua | 64 | import p, to_lua from "yue" |
55 | 65 | ||
56 | -- éšå¼å¯¹è±¡ | 66 | -- éšå¼å¯¹è±¡ |
57 | inventory = | 67 | inventory = |
58 | equipment: | 68 | equipment: |
59 | * "sword" | 69 | - "sword" |
60 | * "shield" | 70 | - "shield" |
61 | items: | 71 | items: |
62 | * name: "potion" | 72 | - name: "potion" |
63 | count: 10 | 73 | count: 10 |
64 | * name: "bread" | 74 | - name: "bread" |
65 | count: 3 | 75 | count: 3 |
66 | 76 | ||
77 | -- 列表推导 | ||
78 | map = (arr, action) -> | ||
79 | [action item for item in *arr] | ||
80 | |||
81 | filter = (arr, cond) -> | ||
82 | [item for item in *arr when cond item] | ||
83 | |||
84 | reduce = (arr, init, action): init -> | ||
85 | init = action init, item for item in *arr | ||
86 | |||
67 | -- ç®¡é“æ“作符 | 87 | -- ç®¡é“æ“作符 |
68 | [1, 2, 3] | 88 | [1, 2, 3] |
69 | |> map (x) -> x * 2 | 89 | |> map (x) -> x * 2 |
@@ -122,7 +142,7 @@ export 🌛 = "月之脚本" | |||
122 | 142 | ||
123 | * **下载预编译的二进制程åº** | 143 | * **下载预编译的二进制程åº** |
124 | 144 | ||
125 |  您å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。 | 145 |  ä½ å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。 |
126 | 146 | ||
127 |  在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚ | 147 |  在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚ |
128 | 148 | ||
@@ -132,14 +152,14 @@ export 🌛 = "月之脚本" | |||
132 | 152 | ||
133 | 在Luaä¸ä½¿ç”¨æœˆä¹‹è„šæœ¬æ¨¡å—: | 153 | 在Luaä¸ä½¿ç”¨æœˆä¹‹è„šæœ¬æ¨¡å—: |
134 | 154 | ||
135 | * **用法 1** | 155 | * **用法 1** |
136 | 在Luaä¸å¼•å…¥ "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。 | 156 | 在Luaä¸å¼•å…¥ "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。 |
137 | ```Lua | 157 | ```Lua |
138 | require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶") | 158 | require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶") |
139 | ``` | 159 | ``` |
140 | å½“ä½ åœ¨åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件ä¸ï¼Œåªéœ€æ£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸çš„代ç 行å·ä¹Ÿä¼šè¢«æ£ç¡®å¤„ç†ã€‚ | 160 | å½“ä½ åœ¨åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件ä¸ï¼Œåªéœ€æ£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸çš„代ç 行å·ä¹Ÿä¼šè¢«æ£ç¡®å¤„ç†ã€‚ |
141 | 161 | ||
142 | * **用法 2** | 162 | * **用法 2** |
143 | 手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚ | 163 | 手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚ |
144 | ```lua | 164 | ```lua |
145 | local yue = require("yue") | 165 | local yue = require("yue") |
@@ -151,7 +171,7 @@ end, function(err) | |||
151 | end) | 171 | end) |
152 | ``` | 172 | ``` |
153 | 173 | ||
154 | * **用法 3** | 174 | * **用法 3** |
155 | 在Luaä¸ä½¿ç”¨æœˆä¹‹è„šæœ¬ç¼–è¯‘å™¨åŠŸèƒ½ã€‚ | 175 | 在Luaä¸ä½¿ç”¨æœˆä¹‹è„šæœ¬ç¼–è¯‘å™¨åŠŸèƒ½ã€‚ |
156 | ```lua | 176 | ```lua |
157 | local yue = require("yue") | 177 | local yue = require("yue") |
@@ -202,12 +222,12 @@ f! | |||
202 | 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ | 222 | 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ |
203 | 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ¢å¤šè¡Œè¾“å…¥æ¨¡å¼ | 223 | 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ¢å¤šè¡Œè¾“å…¥æ¨¡å¼ |
204 | ``` | 224 | ``` |
205 |   使用案例: | 225 |   使用案例: |
206 |   递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .** | 226 |   递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .** |
207 |   编译并将结果ä¿å˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .** | 227 |   编译并将结果ä¿å˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .** |
208 |   编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .** | 228 |   编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .** |
209 |   编译并生æˆåŽ‹ç¼©ä»£ç : **yue -m .** | 229 |   编译并生æˆåŽ‹ç¼©ä»£ç : **yue -m .** |
210 |   直接执行代ç : **yue -e 'print 123'** | 230 |   直接执行代ç : **yue -e 'print 123'** |
211 |   执行一个月之脚本文件: **yue -e main.yue** | 231 |   执行一个月之脚本文件: **yue -e main.yue** |
212 | 232 | ||
213 | ## å® | 233 | ## å® |
@@ -333,7 +353,7 @@ end | |||
333 | 353 | ||
334 | ### å¯¼å‡ºå® | 354 | ### å¯¼å‡ºå® |
335 | 355 | ||
336 | å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—ä¸å¯¼å‡ºï¼Œå¹¶åœ¨å¦ä¸€ä¸ªæ¨¡å—ä¸å¯¼å…¥ã€‚您必须将导出的å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•独的文件ä¸ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—ä¸ã€‚ | 356 | å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—ä¸å¯¼å‡ºï¼Œå¹¶åœ¨å¦ä¸€ä¸ªæ¨¡å—ä¸å¯¼å…¥ã€‚ä½ å¿…é¡»å°†å¯¼å‡ºçš„å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•独的文件ä¸ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—ä¸ã€‚ |
337 | ```moonscript | 357 | ```moonscript |
338 | -- 文件: utils.yue | 358 | -- 文件: utils.yue |
339 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" | 359 | export macro map = (items, action) -> "[#{action} for _ in *#{items}]" |
@@ -422,6 +442,54 @@ print "有效的枚举类型:", $BodyType Static | |||
422 | </pre> | 442 | </pre> |
423 | </YueDisplay> | 443 | </YueDisplay> |
424 | 444 | ||
445 | ### å®å‚数检查 | ||
446 | |||
447 | å¯ä»¥ç›´æŽ¥åœ¨å‚数列表ä¸å£°æ˜ŽæœŸæœ›çš„ AST èŠ‚ç‚¹ç±»åž‹ï¼Œå¹¶åœ¨ç¼–è¯‘æ—¶æ£€æŸ¥ä¼ å…¥çš„å®å‚数是å¦ç¬¦åˆé¢„期。 | ||
448 | |||
449 | ```moonscript | ||
450 | macro printNumAndStr = (num `Num, str `String) -> | | ||
451 | print( | ||
452 | #{num} | ||
453 | #{str} | ||
454 | ) | ||
455 | |||
456 | $printNumAndStr 123, "hello" | ||
457 | ``` | ||
458 | <YueDisplay> | ||
459 | <pre> | ||
460 | macro printNumAndStr = (num `Num, str `String) -> | | ||
461 | print( | ||
462 | #{num} | ||
463 | #{str} | ||
464 | ) | ||
465 | |||
466 | $printNumAndStr 123, "hello" | ||
467 | </pre> | ||
468 | </YueDisplay> | ||
469 | |||
470 | 如果需è¦åšæ›´åŠ çµæ´»çš„傿•°æ£€æŸ¥æ“作,å¯ä»¥ä½¿ç”¨å†…置的 `$is_ast` å®å‡½æ•°åœ¨åˆé€‚çš„ä½ç½®è¿›è¡Œæ‰‹åŠ¨æ£€æŸ¥ã€‚ | ||
471 | |||
472 | ```moonscript | ||
473 | macro printNumAndStr = (num, str) -> | ||
474 | error "expected Num as first argument" unless $is_ast Num, num | ||
475 | error "expected String as second argument" unless $is_ast String, str | ||
476 | "print(#{num}, #{str})" | ||
477 | |||
478 | $printNumAndStr 123, "hello" | ||
479 | ``` | ||
480 | <YueDisplay> | ||
481 | <pre> | ||
482 | macro printNumAndStr = (num, str) -> | ||
483 | error "expected Num as first argument" unless $is_ast Num, num | ||
484 | error "expected String as second argument" unless $is_ast String, str | ||
485 | "print(#{num}, #{str})" | ||
486 | |||
487 | $printNumAndStr 123, "hello" | ||
488 | </pre> | ||
489 | </YueDisplay> | ||
490 | |||
491 | 更多关于å¯ç”¨ AST 节点的详细信æ¯ï¼Œè¯·å‚考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) ä¸å¤§å†™çš„规则定义。 | ||
492 | |||
425 | ## æ“作符 | 493 | ## æ“作符 |
426 | 494 | ||
427 | Lua的所有二元和一元æ“作符在月之脚本ä¸éƒ½æ˜¯å¯ç”¨çš„。æ¤å¤–,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。æ¤å¤–月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç 。 | 495 | Lua的所有二元和一元æ“作符在月之脚本ä¸éƒ½æ˜¯å¯ç”¨çš„。æ¤å¤–,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。æ¤å¤–月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç 。 |
@@ -439,7 +507,7 @@ tb::func! if tb != nil | |||
439 | 507 | ||
440 | ### 链弿¯”较 | 508 | ### 链弿¯”较 |
441 | 509 | ||
442 | 您å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸è¿›è¡Œæ¯”较表达å¼çš„链å¼ä¹¦å†™ï¼š | 510 | ä½ å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸è¿›è¡Œæ¯”较表达å¼çš„链å¼ä¹¦å†™ï¼š |
443 | 511 | ||
444 | ```moonscript | 512 | ```moonscript |
445 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 | 513 | print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 |
@@ -528,7 +596,7 @@ tab[] = "Value" | |||
528 | 596 | ||
529 | ### 表扩展 | 597 | ### 表扩展 |
530 | 598 | ||
531 | 您å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Luaè¡¨ä¸æ’入数组表或哈希表。 | 599 | ä½ å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Luaè¡¨ä¸æ’入数组表或哈希表。 |
532 | 600 | ||
533 | ```moonscript | 601 | ```moonscript |
534 | parts = | 602 | parts = |
@@ -565,11 +633,26 @@ merge = {...a, ...b} | |||
565 | </pre> | 633 | </pre> |
566 | </YueDisplay> | 634 | </YueDisplay> |
567 | 635 | ||
636 | ### 表åå‘索引 | ||
637 | |||
638 | ä½ å¯ä»¥ä½¿ç”¨ **#** æ“作符æ¥åå‘索引表ä¸çš„å…ƒç´ ã€‚ | ||
639 | |||
640 | ```moonscript | ||
641 | last = data.items[#] | ||
642 | second_last = data.items[#-1] | ||
643 | ``` | ||
644 | <YueDisplay> | ||
645 | <pre> | ||
646 | last = data.items[#] | ||
647 | second_last = data.items[#-1] | ||
648 | </pre> | ||
649 | </YueDisplay> | ||
650 | |||
568 | ### 元表 | 651 | ### 元表 |
569 | 652 | ||
570 | **<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚ | 653 | **<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚ |
571 | 654 | ||
572 | * **元表创建** | 655 | * **元表创建** |
573 | ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。 | 656 | ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。 |
574 | 657 | ||
575 | ```moonscript | 658 | ```moonscript |
@@ -605,7 +688,7 @@ close _ = <close>: -> print "超出范围" | |||
605 | </pre> | 688 | </pre> |
606 | </YueDisplay> | 689 | </YueDisplay> |
607 | 690 | ||
608 | * **元表访问** | 691 | * **元表访问** |
609 | 使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** ä¸ç¼–写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚ | 692 | 使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** ä¸ç¼–写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚ |
610 | 693 | ||
611 | ```moonscript | 694 | ```moonscript |
@@ -629,7 +712,7 @@ print tb.item | |||
629 | </pre> | 712 | </pre> |
630 | </YueDisplay> | 713 | </YueDisplay> |
631 | 714 | ||
632 | * **元表解构** | 715 | * **元表解构** |
633 | 使用被 **<>** 包围的元方法键解构元表。 | 716 | 使用被 **<>** 包围的元方法键解构元表。 |
634 | 717 | ||
635 | ```moonscript | 718 | ```moonscript |
@@ -680,7 +763,7 @@ with? io.open "test.txt", "w" | |||
680 | 763 | ||
681 | ### ç®¡é“ | 764 | ### ç®¡é“ |
682 | 765 | ||
683 | 与其使用一系列嵌套的函数调用,您还å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ 递值。 | 766 | ä¸Žå…¶ä½¿ç”¨ä¸€ç³»åˆ—åµŒå¥—çš„å‡½æ•°è°ƒç”¨ï¼Œä½ è¿˜å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ 递值。 |
684 | 767 | ||
685 | ```moonscript | 768 | ```moonscript |
686 | "ä½ å¥½" |> print | 769 | "ä½ å¥½" |> print |
@@ -731,67 +814,87 @@ a ??= false | |||
731 | 814 | ||
732 | ### éšå¼å¯¹è±¡ | 815 | ### éšå¼å¯¹è±¡ |
733 | 816 | ||
734 | 您å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 开始编写一系列éšå¼ç»“构。如果您æ£åœ¨åˆ›å»ºéšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„å—æ®µå¿…须具有相åŒçš„缩进。 | 817 | ä½ å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 或是 **-** 开始编写一系列éšå¼ç»“æž„ã€‚å¦‚æžœä½ æ£åœ¨åˆ›å»ºéšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„å—æ®µå¿…须具有相åŒçš„缩进。 |
818 | |||
735 | ```moonscript | 819 | ```moonscript |
820 | -- 赋值时使用éšå¼å¯¹è±¡ | ||
736 | list = | 821 | list = |
737 | * 1 | 822 | * 1 |
738 | * 2 | 823 | * 2 |
739 | * 3 | 824 | * 3 |
740 | 825 | ||
826 | -- 函数调用时使用éšå¼å¯¹è±¡ | ||
741 | func | 827 | func |
742 | * 1 | 828 | * 1 |
743 | * 2 | 829 | * 2 |
744 | * 3 | 830 | * 3 |
745 | 831 | ||
832 | -- 返回时使用éšå¼å¯¹è±¡ | ||
833 | f = -> | ||
834 | return | ||
835 | * 1 | ||
836 | * 2 | ||
837 | * 3 | ||
838 | |||
839 | -- è¡¨æ ¼æ—¶ä½¿ç”¨éšå¼å¯¹è±¡ | ||
746 | tb = | 840 | tb = |
747 | name: "abc" | 841 | name: "abc" |
748 | 842 | ||
749 | values: | 843 | values: |
750 | * "a" | 844 | - "a" |
751 | * "b" | 845 | - "b" |
752 | * "c" | 846 | - "c" |
753 | 847 | ||
754 | objects: | 848 | objects: |
755 | * name: "a" | 849 | - name: "a" |
756 | value: 1 | 850 | value: 1 |
757 | func: => @value + 1 | 851 | func: => @value + 1 |
758 | tb: | 852 | tb: |
759 | fieldA: 1 | 853 | fieldA: 1 |
760 | 854 | ||
761 | * name: "b" | 855 | - name: "b" |
762 | value: 2 | 856 | value: 2 |
763 | func: => @value + 2 | 857 | func: => @value + 2 |
764 | tb: { } | 858 | tb: { } |
765 | |||
766 | ``` | 859 | ``` |
767 | <YueDisplay> | 860 | <YueDisplay> |
768 | <pre> | 861 | <pre> |
862 | -- 赋值时使用éšå¼å¯¹è±¡ | ||
769 | list = | 863 | list = |
770 | * 1 | 864 | * 1 |
771 | * 2 | 865 | * 2 |
772 | * 3 | 866 | * 3 |
773 | 867 | ||
868 | -- 函数调用时使用éšå¼å¯¹è±¡ | ||
774 | func | 869 | func |
775 | * 1 | 870 | * 1 |
776 | * 2 | 871 | * 2 |
777 | * 3 | 872 | * 3 |
778 | 873 | ||
874 | -- 返回时使用éšå¼å¯¹è±¡ | ||
875 | f = -> | ||
876 | return | ||
877 | * 1 | ||
878 | * 2 | ||
879 | * 3 | ||
880 | |||
881 | -- è¡¨æ ¼æ—¶ä½¿ç”¨éšå¼å¯¹è±¡ | ||
779 | tb = | 882 | tb = |
780 | name: "abc" | 883 | name: "abc" |
781 | 884 | ||
782 | values: | 885 | values: |
783 | * "a" | 886 | - "a" |
784 | * "b" | 887 | - "b" |
785 | * "c" | 888 | - "c" |
786 | 889 | ||
787 | objects: | 890 | objects: |
788 | * name: "a" | 891 | - name: "a" |
789 | value: 1 | 892 | value: 1 |
790 | func: => @value + 1 | 893 | func: => @value + 1 |
791 | tb: | 894 | tb: |
792 | fieldA: 1 | 895 | fieldA: 1 |
793 | 896 | ||
794 | * name: "b" | 897 | - name: "b" |
795 | value: 2 | 898 | value: 2 |
796 | func: => @value + 2 | 899 | func: => @value + 2 |
797 | tb: { } | 900 | tb: { } |
@@ -859,7 +962,7 @@ do | |||
859 | 962 | ||
860 | 导出è¯å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。 | 963 | 导出è¯å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。 |
861 | 964 | ||
862 | * **命å导出** | 965 | * **命å导出** |
863 | 带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„è¡¨ä¸æ·»åŠ ä¸€ä¸ªåŒåçš„å—æ®µã€‚ | 966 | 带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„è¡¨ä¸æ·»åŠ ä¸€ä¸ªåŒåçš„å—æ®µã€‚ |
864 | 967 | ||
865 | ```moonscript | 968 | ```moonscript |
@@ -923,7 +1026,7 @@ export["a-b-c"] = 123 | |||
923 | </pre> | 1026 | </pre> |
924 | </YueDisplay> | 1027 | </YueDisplay> |
925 | 1028 | ||
926 | * **未命å导出** | 1029 | * **未命å导出** |
927 | 未命å导出会将è¦å¯¼å‡ºçš„ç›®æ ‡é¡¹ç›®æ·»åŠ åˆ°å¯¼å‡ºè¡¨çš„æ•°ç»„éƒ¨åˆ†ã€‚ | 1030 | 未命å导出会将è¦å¯¼å‡ºçš„ç›®æ ‡é¡¹ç›®æ·»åŠ åˆ°å¯¼å‡ºè¡¨çš„æ•°ç»„éƒ¨åˆ†ã€‚ |
928 | 1031 | ||
929 | ```moonscript | 1032 | ```moonscript |
@@ -953,7 +1056,7 @@ export with tmp | |||
953 | </pre> | 1056 | </pre> |
954 | </YueDisplay> | 1057 | </YueDisplay> |
955 | 1058 | ||
956 | * **默认导出** | 1059 | * **默认导出** |
957 | 在导出è¯å¥ä¸ä½¿ç”¨ **default** 关键å—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„è¡¨ä¸ºä¸€ä¸ªç›®æ ‡çš„å¯¹è±¡ã€‚ | 1060 | 在导出è¯å¥ä¸ä½¿ç”¨ **default** 关键å—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„è¡¨ä¸ºä¸€ä¸ªç›®æ ‡çš„å¯¹è±¡ã€‚ |
958 | 1061 | ||
959 | ```moonscript | 1062 | ```moonscript |
@@ -1223,7 +1326,7 @@ print first, second, color | |||
1223 | </pre> | 1326 | </pre> |
1224 | </YueDisplay> | 1327 | </YueDisplay> |
1225 | 1328 | ||
1226 | 在进行解构时,您å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚: | 1329 | åœ¨è¿›è¡Œè§£æž„æ—¶ï¼Œä½ å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚: |
1227 | 1330 | ||
1228 | ```moonscript | 1331 | ```moonscript |
1229 | {:name = "nameless", :job = "jobless"} = person | 1332 | {:name = "nameless", :job = "jobless"} = person |
@@ -1234,7 +1337,7 @@ print first, second, color | |||
1234 | </pre> | 1337 | </pre> |
1235 | </YueDisplay> | 1338 | </YueDisplay> |
1236 | 1339 | ||
1237 | 在进行列表解构时,您å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š | 1340 | åœ¨è¿›è¡Œåˆ—è¡¨è§£æž„æ—¶ï¼Œä½ å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š |
1238 | 1341 | ||
1239 | ```moonscript | 1342 | ```moonscript |
1240 | [_, two, _, four] = items | 1343 | [_, two, _, four] = items |
@@ -1245,9 +1348,55 @@ print first, second, color | |||
1245 | </pre> | 1348 | </pre> |
1246 | </YueDisplay> | 1349 | </YueDisplay> |
1247 | 1350 | ||
1248 | ### 在其它地方的解构 | 1351 | ### 范围解构 |
1352 | |||
1353 | ä½ å¯ä»¥ä½¿ç”¨å±•å¼€è¿ç®—符 `...` åœ¨åˆ—è¡¨è§£æž„ä¸æ¥æ•获一个范围的值到å列表ä¸ã€‚è¿™åœ¨å½“ä½ æƒ³è¦ä»Žåˆ—表的开头和结尾æå–ç‰¹å®šå…ƒç´ ï¼ŒåŒæ—¶æ”¶é›†ä¸é—´çš„å…ƒç´ æ—¶éžå¸¸æœ‰ç”¨ã€‚ | ||
1354 | |||
1355 | ```moonscript | ||
1356 | orders = ["first", "second", "third", "fourth", "last"] | ||
1357 | [first, ...bulk, last] = orders | ||
1358 | print first -- 打å°: first | ||
1359 | print bulk -- 打å°: {"second", "third", "fourth"} | ||
1360 | print last -- 打å°: last | ||
1361 | ``` | ||
1362 | <YueDisplay> | ||
1363 | <pre> | ||
1364 | orders = ["first", "second", "third", "fourth", "last"] | ||
1365 | [first, ...bulk, last] = orders | ||
1366 | print first -- 打å°: first | ||
1367 | print bulk -- 打å°: {"second", "third", "fourth"} | ||
1368 | print last -- 打å°: last | ||
1369 | </pre> | ||
1370 | </YueDisplay> | ||
1371 | |||
1372 | 展开è¿ç®—符å¯ä»¥ç”¨åœ¨ä¸åŒçš„ä½ç½®æ¥æ•获ä¸åŒçš„èŒƒå›´ï¼Œå¹¶ä¸”ä½ å¯ä»¥ä½¿ç”¨ `_` 作为å ä½ç¬¦æ¥è¡¨ç¤ºä½ 想跳过对应范围的æ•获: | ||
1373 | |||
1374 | ```moonscript | ||
1375 | -- æ•èŽ·ç¬¬ä¸€ä¸ªå…ƒç´ ä¹‹åŽçš„æ‰€æœ‰å…ƒç´ | ||
1376 | [first, ...rest] = orders | ||
1377 | |||
1378 | -- æ•获最åŽä¸€ä¸ªå…ƒç´ 之å‰çš„æ‰€æœ‰å…ƒç´ | ||
1379 | [...start, last] = orders | ||
1380 | |||
1381 | -- 跳过ä¸é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ | ||
1382 | [first, ..._, last] = orders | ||
1383 | ``` | ||
1384 | <YueDisplay> | ||
1385 | <pre> | ||
1386 | -- æ•èŽ·ç¬¬ä¸€ä¸ªå…ƒç´ ä¹‹åŽçš„æ‰€æœ‰å…ƒç´ | ||
1387 | [first, ...rest] = orders | ||
1388 | |||
1389 | -- æ•获最åŽä¸€ä¸ªå…ƒç´ 之å‰çš„æ‰€æœ‰å…ƒç´ | ||
1390 | [...start, last] = orders | ||
1391 | |||
1392 | -- 跳过ä¸é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ | ||
1393 | [first, ..._, last] = orders | ||
1394 | </pre> | ||
1395 | </YueDisplay> | ||
1396 | |||
1397 | ### 在其它地方的解构赋值 | ||
1249 | 1398 | ||
1250 | 解构也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹åæ˜¯ç”¨åœ¨for循环: | 1399 | 解构赋值也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹åæ˜¯ç”¨åœ¨for循环ä¸ï¼š |
1251 | 1400 | ||
1252 | ```moonscript | 1401 | ```moonscript |
1253 | tuples = [ | 1402 | tuples = [ |
@@ -1322,7 +1471,7 @@ print "好的" | |||
1322 | 1471 | ||
1323 | ### While 赋值 | 1472 | ### While 赋值 |
1324 | 1473 | ||
1325 | 您å¯ä»¥åœ¨ while 循环ä¸åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。 | 1474 | ä½ å¯ä»¥åœ¨ while 循环ä¸åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。 |
1326 | ```moonscript | 1475 | ```moonscript |
1327 | while byte := stream\read_one! | 1476 | while byte := stream\read_one! |
1328 | -- 对 byte åšä¸€äº›æ“作 | 1477 | -- 对 byte åšä¸€äº›æ“作 |
@@ -1338,7 +1487,7 @@ while byte := stream\read_one! | |||
1338 | 1487 | ||
1339 | ## å¯å˜å‚数赋值 | 1488 | ## å¯å˜å‚数赋值 |
1340 | 1489 | ||
1341 | 您å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。 | 1490 | ä½ å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。 |
1342 | ```moonscript | 1491 | ```moonscript |
1343 | list = [1, 2, 3, 4, 5] | 1492 | list = [1, 2, 3, 4, 5] |
1344 | fn = (ok) -> ok, table.unpack list | 1493 | fn = (ok) -> ok, table.unpack list |
@@ -1360,7 +1509,7 @@ print ok, count, first | |||
1360 | 1509 | ||
1361 | ## 空白 | 1510 | ## 空白 |
1362 | 1511 | ||
1363 | æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„è¯è¨€ã€‚您必须在相åŒçš„缩进ä¸ä½¿ç”¨ç©ºæ ¼ **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4ä¸ªç©ºæ ¼ï¼Œä½†æœ€å¥½ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚ | 1512 | æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„è¯è¨€ã€‚ä½ å¿…é¡»åœ¨ç›¸åŒçš„缩进ä¸ä½¿ç”¨ç©ºæ ¼ **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4ä¸ªç©ºæ ¼ï¼Œä½†æœ€å¥½ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚ |
1364 | 1513 | ||
1365 | ### 多行链å¼è°ƒç”¨ | 1514 | ### 多行链å¼è°ƒç”¨ |
1366 | 1515 | ||
@@ -1474,6 +1623,47 @@ catch err | |||
1474 | </pre> | 1623 | </pre> |
1475 | </YueDisplay> | 1624 | </YueDisplay> |
1476 | 1625 | ||
1626 | ### 错误处ç†ç®€åŒ– | ||
1627 | |||
1628 | `try?` 是 `try` çš„åŠŸèƒ½ç®€åŒ–è¯æ³•,它ä¸å†è¿”回 `try` è¯å¥çš„布尔状æ€ï¼Œå¹¶åœ¨æˆåŠŸæ—¶ç›´æŽ¥è¿”å›ž `try` 代ç å—的结果,失败时返回 `nil` 值而éžé”™è¯¯å¯¹è±¡ã€‚ | ||
1629 | |||
1630 | ```moonscript | ||
1631 | a, b, c = try? func! | ||
1632 | |||
1633 | -- 与空值åˆå¹¶è¿ç®—符一起使用 | ||
1634 | a = (try? func!) ?? "default" | ||
1635 | |||
1636 | -- ä½œä¸ºå‡½æ•°å‚æ•° | ||
1637 | f try? func! | ||
1638 | |||
1639 | -- 带 catch å—çš„ try! | ||
1640 | f try? | ||
1641 | print 123 | ||
1642 | func! | ||
1643 | catch e | ||
1644 | print e | ||
1645 | e | ||
1646 | ``` | ||
1647 | <YueDisplay> | ||
1648 | <pre> | ||
1649 | a, b, c = try? func! | ||
1650 | |||
1651 | -- 与空值åˆå¹¶è¿ç®—符一起使用 | ||
1652 | a = (try? func!) ?? "default" | ||
1653 | |||
1654 | -- ä½œä¸ºå‡½æ•°å‚æ•° | ||
1655 | f try? func! | ||
1656 | |||
1657 | -- 带 catch å—çš„ try! | ||
1658 | f try? | ||
1659 | print 123 | ||
1660 | func! | ||
1661 | catch e | ||
1662 | print e | ||
1663 | e | ||
1664 | </pre> | ||
1665 | </YueDisplay> | ||
1666 | |||
1477 | ## 属性 | 1667 | ## 属性 |
1478 | 1668 | ||
1479 | 月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„è¯æ³•支æŒã€‚在月之脚本编译到的Luaç›®æ ‡ç‰ˆæœ¬ä½ŽäºŽ5.4æ—¶ï¼Œä½ ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。 | 1669 | 月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„è¯æ³•支æŒã€‚在月之脚本编译到的Luaç›®æ ‡ç‰ˆæœ¬ä½ŽäºŽ5.4æ—¶ï¼Œä½ ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。 |
@@ -1502,6 +1692,19 @@ const {:a, :b, c, d} = tb | |||
1502 | </pre> | 1692 | </pre> |
1503 | </YueDisplay> | 1693 | </YueDisplay> |
1504 | 1694 | ||
1695 | ä½ ä¹Ÿå¯ä»¥å£°æ˜Žå…¨å±€å˜é‡ä¸ºå¸¸é‡ã€‚ | ||
1696 | |||
1697 | ```moonscript | ||
1698 | global const Constant = 123 | ||
1699 | -- Constant = 1 | ||
1700 | ``` | ||
1701 | <YueDisplay> | ||
1702 | <pre> | ||
1703 | global const Constant = 123 | ||
1704 | -- Constant = 1 | ||
1705 | </pre> | ||
1706 | </YueDisplay> | ||
1707 | |||
1505 | ## å—é¢é‡ | 1708 | ## å—é¢é‡ |
1506 | 1709 | ||
1507 | Luaä¸çš„æ‰€æœ‰åŸºæœ¬å—é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸ä½¿ç”¨ã€‚包括数å—ã€å—符串ã€å¸ƒå°”值和**nil**。 | 1710 | Luaä¸çš„æ‰€æœ‰åŸºæœ¬å—é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸ä½¿ç”¨ã€‚包括数å—ã€å—符串ã€å¸ƒå°”值和**nil**。 |
@@ -1529,17 +1732,78 @@ print "我有#{math.random! * 100}%的把æ¡ã€‚" | |||
1529 | 1732 | ||
1530 | ### æ•°å—å—é¢é‡ | 1733 | ### æ•°å—å—é¢é‡ |
1531 | 1734 | ||
1532 | 您å¯ä»¥åœ¨æ•°å—å—é¢é‡ä¸ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚ | 1735 | ä½ å¯ä»¥åœ¨æ•°å—å—é¢é‡ä¸ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚ |
1533 | 1736 | ||
1534 | ```moonscript | 1737 | ```moonscript |
1535 | integer = 1_000_000 | 1738 | integer = 1_000_000 |
1536 | hex = 0xEF_BB_BF | 1739 | hex = 0xEF_BB_BF |
1740 | binary = 0B10011 | ||
1537 | ``` | 1741 | ``` |
1538 | <YueDisplay> | 1742 | <YueDisplay> |
1539 | 1743 | ||
1540 | <pre> | 1744 | <pre> |
1541 | integer = 1_000_000 | 1745 | integer = 1_000_000 |
1542 | hex = 0xEF_BB_BF | 1746 | hex = 0xEF_BB_BF |
1747 | binary = 0B10011 | ||
1748 | </pre> | ||
1749 | </YueDisplay> | ||
1750 | |||
1751 | ### YAML é£Žæ ¼å—符串 | ||
1752 | |||
1753 | 使用 `|` å‰ç¼€æ ‡è®°ä¸€ä¸ªå¤šè¡Œ YAML é£Žæ ¼å—符串: | ||
1754 | |||
1755 | ```moonscript | ||
1756 | str = | | ||
1757 | key: value | ||
1758 | list: | ||
1759 | - item1 | ||
1760 | - #{expr} | ||
1761 | ``` | ||
1762 | <YueDisplay> | ||
1763 | <pre> | ||
1764 | str = | | ||
1765 | key: value | ||
1766 | list: | ||
1767 | - item1 | ||
1768 | - #{expr} | ||
1769 | </pre> | ||
1770 | </YueDisplay> | ||
1771 | |||
1772 | 其效果类似于原生 Lua çš„å¤šè¡Œæ‹¼æŽ¥ï¼Œæ‰€æœ‰æ–‡æœ¬ï¼ˆå«æ¢è¡Œï¼‰å°†è¢«ä¿ç•™ä¸‹æ¥ï¼Œå¹¶æ”¯æŒ `#{...}` è¯æ³•,通过 `tostring(expr)` æ’入表达å¼ç»“果。 | ||
1773 | |||
1774 | YAML é£Žæ ¼çš„å¤šè¡Œå—ç¬¦ä¸²ä¼šè‡ªåŠ¨æ£€æµ‹é¦–è¡ŒåŽæœ€å°çš„公共缩进,并从所有行ä¸åˆ 除该å‰ç¼€ç©ºç™½å—ç¬¦ã€‚è¿™è®©ä½ å¯ä»¥åœ¨ä»£ç ä¸å¯¹é½æ–‡æœ¬ï¼Œä½†è¾“出å—符串ä¸ä¼šå¸¦å¤šä½™ç¼©è¿›ã€‚ | ||
1775 | |||
1776 | ```moonscript | ||
1777 | fn = -> | ||
1778 | str = | | ||
1779 | foo: | ||
1780 | bar: baz | ||
1781 | return str | ||
1782 | ``` | ||
1783 | <YueDisplay> | ||
1784 | <pre> | ||
1785 | fn = -> | ||
1786 | str = | | ||
1787 | foo: | ||
1788 | bar: baz | ||
1789 | return str | ||
1790 | </pre> | ||
1791 | </YueDisplay> | ||
1792 | |||
1793 | 输出å—符串ä¸çš„ foo: 对é½åˆ°è¡Œé¦–,ä¸ä¼šå¸¦æœ‰å‡½æ•°ç¼©è¿›ç©ºæ ¼ã€‚ä¿ç•™å†…部缩进的相对结构,适åˆä¹¦å†™ç»“æž„åŒ–åµŒå¥—æ ·å¼çš„内容。 | ||
1794 | |||
1795 | 支æŒè‡ªåЍ处ç†å—符ä¸çš„引å·ã€åæ–œæ ç‰ç‰¹æ®Šç¬¦å·ï¼Œæ— 需手动转义: | ||
1796 | |||
1797 | ```moonscript | ||
1798 | str = | | ||
1799 | path: "C:\Program Files\App" | ||
1800 | note: 'He said: "#{Hello}!"' | ||
1801 | ``` | ||
1802 | <YueDisplay> | ||
1803 | <pre> | ||
1804 | str = | | ||
1805 | path: "C:\Program Files\App" | ||
1806 | note: 'He said: "#{Hello}!"' | ||
1543 | </pre> | 1807 | </pre> |
1544 | </YueDisplay> | 1808 | </YueDisplay> |
1545 | 1809 | ||
@@ -1644,7 +1908,7 @@ print "æ•°å—的和是", sum 10, 20 | |||
1644 | </pre> | 1908 | </pre> |
1645 | </YueDisplay> | 1909 | </YueDisplay> |
1646 | 1910 | ||
1647 | 如果您需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键å—: | 1911 | å¦‚æžœä½ éœ€è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键å—: |
1648 | 1912 | ||
1649 | ```moonscript | 1913 | ```moonscript |
1650 | sum = (x, y) -> return x + y | 1914 | sum = (x, y) -> return x + y |
@@ -1850,7 +2114,7 @@ print @value | |||
1850 | </pre> | 2114 | </pre> |
1851 | </YueDisplay> | 2115 | </YueDisplay> |
1852 | 2116 | ||
1853 | 您å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚ | 2117 | ä½ å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚ |
1854 | 2118 | ||
1855 | ```moonscript | 2119 | ```moonscript |
1856 | (x) <- map _, [1, 2, 3] | 2120 | (x) <- map _, [1, 2, 3] |
@@ -1863,22 +2127,22 @@ x * 2 | |||
1863 | </pre> | 2127 | </pre> |
1864 | </YueDisplay> | 2128 | </YueDisplay> |
1865 | 2129 | ||
1866 | 如果您希望在åå‘回调处ç†åŽç»§ç»ç¼–写更多其它的代ç ,您å¯ä»¥ä½¿ç”¨doè¯å¥å°†ä¸å½’属åå‘回调的代ç 分开。 | 2130 | å¦‚æžœä½ å¸Œæœ›åœ¨åå‘回调处ç†åŽç»§ç»ç¼–写更多其它的代ç ,å¯ä»¥ä½¿ç”¨ do è¯å¥å°†ä¸å±žäºŽåå‘回调的代ç 分隔开。对于éžç²—ç®å¤´å‡½æ•°çš„åå‘回调,回调返回值的括å·ä¹Ÿæ˜¯å¯ä»¥çœç•¥çš„。 |
1867 | 2131 | ||
1868 | ```moonscript | 2132 | ```moonscript |
1869 | result, msg = do | 2133 | result, msg = do |
1870 | (data) <- readAsync "文件å.txt" | 2134 | data <- readAsync "文件å.txt" |
1871 | print data | 2135 | print data |
1872 | (info) <- processAsync data | 2136 | info <- processAsync data |
1873 | check info | 2137 | check info |
1874 | print result, msg | 2138 | print result, msg |
1875 | ``` | 2139 | ``` |
1876 | <YueDisplay> | 2140 | <YueDisplay> |
1877 | <pre> | 2141 | <pre> |
1878 | result, msg = do | 2142 | result, msg = do |
1879 | (data) <- readAsync "文件å.txt" | 2143 | data <- readAsync "文件å.txt" |
1880 | print data | 2144 | print data |
1881 | (info) <- processAsync data | 2145 | info <- processAsync data |
1882 | check info | 2146 | check info |
1883 | print result, msg | 2147 | print result, msg |
1884 | </pre> | 2148 | </pre> |
@@ -2037,7 +2301,7 @@ list_with_one_element = [ 1, ] | |||
2037 | 2301 | ||
2038 | ## æŽ¨å¯¼å¼ | 2302 | ## æŽ¨å¯¼å¼ |
2039 | 2303 | ||
2040 | 推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„è¯æ³•,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Luaè¡¨æ ¼ï¼›åˆ—è¡¨æŽ¨å¯¼å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„çš„è¡¨æ ¼ä¸ï¼Œè€Œè¡¨æ ¼æŽ¨å¯¼å¼å…è®¸æ‚¨åœ¨æ¯æ¬¡éåŽ†æ—¶è®¾ç½®æ–°è¡¨æ ¼çš„é”®å’Œå€¼ã€‚ | 2304 | 推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„è¯æ³•,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Luaè¡¨æ ¼ï¼›åˆ—è¡¨æŽ¨å¯¼å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„çš„è¡¨æ ¼ä¸ï¼Œè€Œè¡¨æ ¼æŽ¨å¯¼å¼å…è®¸ä½ åœ¨æ¯æ¬¡éåŽ†æ—¶è®¾ç½®æ–°è¡¨æ ¼çš„é”®å’Œå€¼ã€‚ |
2041 | 2305 | ||
2042 | ### åˆ—è¡¨æŽ¨å¯¼å¼ | 2306 | ### åˆ—è¡¨æŽ¨å¯¼å¼ |
2043 | 2307 | ||
@@ -2057,13 +2321,11 @@ doubled = [item * 2 for i, item in ipairs items] | |||
2057 | å¯ä»¥ä½¿ç”¨whenåå¥ç›é€‰æ–°è¡¨ä¸åŒ…å«çš„项目: | 2321 | å¯ä»¥ä½¿ç”¨whenåå¥ç›é€‰æ–°è¡¨ä¸åŒ…å«çš„项目: |
2058 | 2322 | ||
2059 | ```moonscript | 2323 | ```moonscript |
2060 | iter = ipairs items | 2324 | slice = [item for i, item in ipairs items when i > 1 and i < 3] |
2061 | slice = [item for i, item in iter when i > 1 and i < 3] | ||
2062 | ``` | 2325 | ``` |
2063 | <YueDisplay> | 2326 | <YueDisplay> |
2064 | <pre> | 2327 | <pre> |
2065 | iter = ipairs items | 2328 | slice = [item for i, item in ipairs items when i > 1 and i < 3] |
2066 | slice = [item for i, item in iter when i > 1 and i < 3] | ||
2067 | </pre> | 2329 | </pre> |
2068 | </YueDisplay> | 2330 | </YueDisplay> |
2069 | 2331 | ||
@@ -2212,6 +2474,45 @@ slice = [item for item in *items[,,2]] | |||
2212 | </pre> | 2474 | </pre> |
2213 | </YueDisplay> | 2475 | </YueDisplay> |
2214 | 2476 | ||
2477 | 最å°å’Œæœ€å¤§è¾¹ç•Œéƒ½å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿ç”¨è´Ÿæ•°æ„味ç€è¾¹ç•Œæ˜¯ä»Žè¡¨çš„æœ«å°¾å¼€å§‹è®¡ç®—的。 | ||
2478 | |||
2479 | ```moonscript | ||
2480 | -- å–æœ€åŽ4ä¸ªå…ƒç´ | ||
2481 | slice = [item for item in *items[-4,-1]] | ||
2482 | ``` | ||
2483 | <YueDisplay> | ||
2484 | <pre> | ||
2485 | -- å–æœ€åŽ4ä¸ªå…ƒç´ | ||
2486 | slice = [item for item in *items[-4,-1]] | ||
2487 | </pre> | ||
2488 | </YueDisplay> | ||
2489 | |||
2490 | 切片的æ¥é•¿ä¹Ÿå¯ä»¥æ˜¯è´Ÿæ•°ï¼Œè¿™æ„味ç€å…ƒç´ 会以相å的顺åºè¢«å–出。 | ||
2491 | |||
2492 | ```moonscript | ||
2493 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
2494 | ``` | ||
2495 | <YueDisplay> | ||
2496 | <pre> | ||
2497 | reverse_slice = [item for item in *items[-1,1,-1]] | ||
2498 | </pre> | ||
2499 | </YueDisplay> | ||
2500 | |||
2501 | #### åˆ‡ç‰‡è¡¨è¾¾å¼ | ||
2502 | |||
2503 | 切片也å¯ä»¥ä½œä¸ºè¡¨è¾¾å¼æ¥ä½¿ç”¨ã€‚å¯ä»¥ç”¨äºŽèŽ·å–一个表包å«çš„å列表。 | ||
2504 | |||
2505 | ```moonscript | ||
2506 | -- å–第2和第4ä¸ªå…ƒç´ ä½œä¸ºæ–°çš„åˆ—è¡¨ | ||
2507 | sub_list = items[2, 4] | ||
2508 | ``` | ||
2509 | <YueDisplay> | ||
2510 | <pre> | ||
2511 | -- å–第2和第4ä¸ªå…ƒç´ ä½œä¸ºæ–°çš„åˆ—è¡¨ | ||
2512 | sub_list = items[2, 4] | ||
2513 | </pre> | ||
2514 | </YueDisplay> | ||
2515 | |||
2215 | ## for 循环 | 2516 | ## for 循环 |
2216 | 2517 | ||
2217 | Lua䏿œ‰ä¸¤ç§for循环形å¼ï¼Œæ•°å—型和通用型: | 2518 | Lua䏿œ‰ä¸¤ç§for循环形å¼ï¼Œæ•°å—型和通用型: |
@@ -2288,9 +2589,24 @@ doubled_evens = for i = 1, 20 | |||
2288 | </pre> | 2589 | </pre> |
2289 | </YueDisplay> | 2590 | </YueDisplay> |
2290 | 2591 | ||
2291 | 您还å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯å¥æ¥è¿‡æ»¤å€¼ã€‚ | 2592 | æ¤å¤–,for循环还支æŒå¸¦è¿”回值的breakè¯å¥ï¼Œè¿™æ ·å¾ªçŽ¯æœ¬èº«å°±å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œåœ¨æ»¡è¶³æ¡ä»¶æ—¶æå‰é€€å‡ºå¹¶è¿”回有æ„义的结果。 |
2292 | 2593 | ||
2293 | 注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼ï¼Œå¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸ä½œä¸ºè¿”回值(相å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥ä½¿ç”¨è¿”回è¯å¥åŠ for循环表达å¼ã€‚ | 2594 | 例如,查找第一个大于10的数å—: |
2595 | |||
2596 | ```moonscript | ||
2597 | first_large = for n in *numbers | ||
2598 | break n if n > 10 | ||
2599 | ``` | ||
2600 | <YueDisplay> | ||
2601 | <pre> | ||
2602 | first_large = for n in *numbers | ||
2603 | break n if n > 10 | ||
2604 | </pre> | ||
2605 | </YueDisplay> | ||
2606 | |||
2607 | ä½ è¿˜å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯å¥æ¥è¿‡æ»¤å€¼ã€‚ | ||
2608 | |||
2609 | 注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼å¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸ä½œä¸ºè¿”回值(相å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥æ˜¾å¼åœ°ä½¿ç”¨è¿”回è¯å¥åŠ for循环表达å¼ã€‚ | ||
2294 | 2610 | ||
2295 | ```moonscript | 2611 | ```moonscript |
2296 | func_a = -> for i = 1, 10 do print i | 2612 | func_a = -> for i = 1, 10 do print i |
@@ -2515,7 +2831,7 @@ print "ä½ çœŸå¹¸è¿ï¼" unless math.random! > 0.1 | |||
2515 | 2831 | ||
2516 | ### èŒƒå›´è¡¨è¾¾å¼ | 2832 | ### èŒƒå›´è¡¨è¾¾å¼ |
2517 | 2833 | ||
2518 | 您å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç 。 | 2834 | ä½ å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç 。 |
2519 | 2835 | ||
2520 | ```moonscript | 2836 | ```moonscript |
2521 | a = 5 | 2837 | a = 5 |
@@ -2588,28 +2904,26 @@ reader\parse_line! until reader\eof! | |||
2588 | 2904 | ||
2589 | ## switch è¯å¥ | 2905 | ## switch è¯å¥ |
2590 | 2906 | ||
2591 | switchè¯å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„ifè¯å¥è€Œæä¾›çš„ç®€å†™è¯æ³•ã€‚è¦æ³¨æ„ç”¨äºŽæ¯”è¾ƒæ£€æŸ¥çš„ç›®æ ‡å€¼åªä¼šè®¡ç®—一次。和ifè¯å¥ä¸€æ ·ï¼Œswitchè¯å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。 | 2907 | switchè¯å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„ifè¯å¥è€Œæä¾›çš„ç®€å†™è¯æ³•ã€‚è¦æ³¨æ„ç”¨äºŽæ¯”è¾ƒæ£€æŸ¥çš„ç›®æ ‡å€¼åªä¼šè®¡ç®—一次。和ifè¯å¥ä¸€æ ·ï¼Œswitchè¯å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。switchè¯å¥ä¸ä¹Ÿå¯ä»¥ä½¿ç”¨èµ‹å€¼è¡¨è¾¾å¼æ¥å‚¨å˜ä¸´æ—¶å˜é‡å€¼ã€‚ |
2592 | 2908 | ||
2593 | ```moonscript | 2909 | ```moonscript |
2594 | name = "Dan" | 2910 | switch name := "Dan" |
2595 | switch name | ||
2596 | when "Robert" | 2911 | when "Robert" |
2597 | print "ä½ æ˜¯Robert" | 2912 | print "ä½ æ˜¯Robert" |
2598 | when "Dan", "Daniel" | 2913 | when "Dan", "Daniel" |
2599 | print "ä½ çš„åå—æ˜¯Dan" | 2914 | print "ä½ çš„åå—æ˜¯Dan" |
2600 | else | 2915 | else |
2601 | print "我ä¸çŸ¥é“ä½ çš„åå—" | 2916 | print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„åå—æ˜¯#{name}" |
2602 | ``` | 2917 | ``` |
2603 | <YueDisplay> | 2918 | <YueDisplay> |
2604 | <pre> | 2919 | <pre> |
2605 | name = "Dan" | 2920 | switch name := "Dan" |
2606 | switch name | ||
2607 | when "Robert" | 2921 | when "Robert" |
2608 | print "ä½ æ˜¯Robert" | 2922 | print "ä½ æ˜¯Robert" |
2609 | when "Dan", "Daniel" | 2923 | when "Dan", "Daniel" |
2610 | print "ä½ çš„åå—æ˜¯Dan" | 2924 | print "ä½ çš„åå—æ˜¯Dan" |
2611 | else | 2925 | else |
2612 | print "我ä¸çŸ¥é“ä½ çš„åå—" | 2926 | print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„åå—æ˜¯#{name}" |
2613 | </pre> | 2927 | </pre> |
2614 | </YueDisplay> | 2928 | </YueDisplay> |
2615 | 2929 | ||
@@ -2686,7 +3000,7 @@ else | |||
2686 | </pre> | 3000 | </pre> |
2687 | </YueDisplay> | 3001 | </YueDisplay> |
2688 | 3002 | ||
2689 | 值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚当您希望给whenåå¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–逻辑时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚ | 3003 | 值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚å½“ä½ å¸Œæœ›ç»™whenåå¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–逻辑时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚ |
2690 | 3004 | ||
2691 | ### è¡¨æ ¼åŒ¹é… | 3005 | ### è¡¨æ ¼åŒ¹é… |
2692 | 3006 | ||
@@ -2746,9 +3060,126 @@ switch item | |||
2746 | </pre> | 3060 | </pre> |
2747 | </YueDisplay> | 3061 | </YueDisplay> |
2748 | 3062 | ||
3063 | ä½ ä¹Ÿå¯ä»¥åŒ¹é…æ•°ç»„å…ƒç´ ã€è¡¨æ ¼å—æ®µï¼Œç”šè‡³ä½¿ç”¨æ•°ç»„æˆ–è¡¨æ ¼å—é¢é‡æ¥åŒ¹é…嵌套的结构。 | ||
3064 | |||
3065 | åŒ¹é…æ•°ç»„å…ƒç´ ã€‚ | ||
3066 | |||
3067 | ```moonscript | ||
3068 | switch tb | ||
3069 | when [1, 2, 3] | ||
3070 | print "1, 2, 3" | ||
3071 | when [1, b, 3] | ||
3072 | print "1, #{b}, 3" | ||
3073 | when [1, 2, b = 3] -- å˜é‡b有默认值 | ||
3074 | print "1, 2, #{b}" | ||
3075 | ``` | ||
3076 | <YueDisplay> | ||
3077 | <pre> | ||
3078 | switch tb | ||
3079 | when [1, 2, 3] | ||
3080 | print "1, 2, 3" | ||
3081 | when [1, b, 3] | ||
3082 | print "1, #{b}, 3" | ||
3083 | when [1, 2, b = 3] -- å˜é‡b有默认值 | ||
3084 | print "1, 2, #{b}" | ||
3085 | </pre> | ||
3086 | </YueDisplay> | ||
3087 | |||
3088 | 匹é…è¡¨æ ¼å—æ®µã€‚ | ||
3089 | |||
3090 | ```moonscript | ||
3091 | switch tb | ||
3092 | when success: true, :result | ||
3093 | print "æˆåŠŸ", result | ||
3094 | when success: false | ||
3095 | print "失败", result | ||
3096 | else | ||
3097 | print "æ— æ•ˆå€¼" | ||
3098 | ``` | ||
3099 | <YueDisplay> | ||
3100 | <pre> | ||
3101 | switch tb | ||
3102 | when success: true, :result | ||
3103 | print "æˆåŠŸ", result | ||
3104 | when success: false | ||
3105 | print "失败", result | ||
3106 | else | ||
3107 | print "æ— æ•ˆå€¼" | ||
3108 | </pre> | ||
3109 | </YueDisplay> | ||
3110 | |||
3111 | 匹é…åµŒå¥—çš„è¡¨æ ¼ç»“æž„ã€‚ | ||
3112 | |||
3113 | ```moonscript | ||
3114 | switch tb | ||
3115 | when data: {type: "success", :content} | ||
3116 | print "æˆåŠŸ", content | ||
3117 | when data: {type: "error", :content} | ||
3118 | print "失败", content | ||
3119 | else | ||
3120 | print "æ— æ•ˆå€¼" | ||
3121 | ``` | ||
3122 | <YueDisplay> | ||
3123 | <pre> | ||
3124 | switch tb | ||
3125 | when data: {type: "success", :content} | ||
3126 | print "æˆåŠŸ", content | ||
3127 | when data: {type: "error", :content} | ||
3128 | print "失败", content | ||
3129 | else | ||
3130 | print "æ— æ•ˆå€¼" | ||
3131 | </pre> | ||
3132 | </YueDisplay> | ||
3133 | |||
3134 | 匹é…è¡¨æ ¼æ•°ç»„ã€‚ | ||
3135 | |||
3136 | ```moonscript | ||
3137 | switch tb | ||
3138 | when [ | ||
3139 | {a: 1, b: 2} | ||
3140 | {a: 3, b: 4} | ||
3141 | {a: 5, b: 6} | ||
3142 | fourth | ||
3143 | ] | ||
3144 | print "åŒ¹é…æˆåŠŸ", fourth | ||
3145 | ``` | ||
3146 | <YueDisplay> | ||
3147 | <pre> | ||
3148 | switch tb | ||
3149 | when [ | ||
3150 | {a: 1, b: 2} | ||
3151 | {a: 3, b: 4} | ||
3152 | {a: 5, b: 6} | ||
3153 | fourth | ||
3154 | ] | ||
3155 | print "åŒ¹é…æˆåŠŸ", fourth | ||
3156 | </pre> | ||
3157 | </YueDisplay> | ||
3158 | |||
3159 | 匹é…一个列表并æ•èŽ·ç‰¹å®šèŒƒå›´å†…çš„å…ƒç´ ã€‚ | ||
3160 | |||
3161 | ```moonscript | ||
3162 | segments = ["admin", "users", "logs", "view"] | ||
3163 | switch segments | ||
3164 | when [...groups, resource, action] | ||
3165 | print "Group:", groups -- 打å°: {"admin", "users"} | ||
3166 | print "Resource:", resource -- 打å°: "logs" | ||
3167 | print "Action:", action -- 打å°: "view" | ||
3168 | ``` | ||
3169 | <YueDisplay> | ||
3170 | <pre> | ||
3171 | segments = ["admin", "users", "logs", "view"] | ||
3172 | switch segments | ||
3173 | when [...groups, resource, action] | ||
3174 | print "Group:", groups -- 打å°: {"admin", "users"} | ||
3175 | print "Resource:", resource -- 打å°: "logs" | ||
3176 | print "Action:", action -- 打å°: "view" | ||
3177 | </pre> | ||
3178 | </YueDisplay> | ||
3179 | |||
2749 | ## é¢å‘对象编程 | 3180 | ## é¢å‘对象编程 |
2750 | 3181 | ||
2751 | 在以下的示例ä¸ï¼Œæœˆä¹‹è„šæœ¬ç”Ÿæˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç 层é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果您想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç 。 | 3182 | 在以下的示例ä¸ï¼Œæœˆä¹‹è„šæœ¬ç”Ÿæˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç 层é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚æžœä½ æƒ³çŸ¥é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç 。 |
2752 | 3183 | ||
2753 | 一个简å•的类: | 3184 | 一个简å•的类: |
2754 | 3185 | ||
@@ -3216,7 +3647,7 @@ x = class | |||
3216 | 3647 | ||
3217 | ### ç±»æ··åˆ | 3648 | ### ç±»æ··åˆ |
3218 | 3649 | ||
3219 | 您å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键嗿¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„å‘³ç€æ‚¨å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua è¡¨æ ¼æˆ–å·²å®šä¹‰çš„ç±»å¯¹è±¡ä¸ï¼Œå¤åˆ¶å‡½æ•°åˆ°æ‚¨åˆ›å»ºçš„æ–°ç±»ä¸ã€‚当您使用普通 Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œæ‚¨æœ‰æœºä¼šç”¨è‡ªå·±çš„实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“æ‚¨ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚ | 3650 | ä½ å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键嗿¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„味ç€ä½ å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua è¡¨æ ¼æˆ–å·²å®šä¹‰çš„ç±»å¯¹è±¡ä¸ï¼Œå¤åˆ¶å‡½æ•°åˆ°ä½ 创建的新类ä¸ã€‚å½“ä½ ä½¿ç”¨æ™®é€š Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œä½ 有机会用自己的实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“ä½ ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚ |
3220 | 3651 | ||
3221 | ```moonscript | 3652 | ```moonscript |
3222 | MyIndex = __index: var: 1 | 3653 | MyIndex = __index: var: 1 |
@@ -3318,22 +3749,22 @@ me = create_person "Leaf", [dad, mother, sister] | |||
3318 | 3749 | ||
3319 | 在æ¤ç”¨æ³•ä¸ï¼Œwithå¯ä»¥è¢«è§†ä¸ºK组åˆå(k-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚ | 3750 | 在æ¤ç”¨æ³•ä¸ï¼Œwithå¯ä»¥è¢«è§†ä¸ºK组åˆå(k-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚ |
3320 | 3751 | ||
3321 | 如果您想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwithè¯å¥ä¸çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯å¥ã€‚ | 3752 | å¦‚æžœä½ æƒ³ç»™è¡¨è¾¾å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwithè¯å¥ä¸çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯å¥ã€‚ |
3322 | 3753 | ||
3323 | ```moonscript | 3754 | ```moonscript |
3324 | with str = "ä½ å¥½" | 3755 | with str := "ä½ å¥½" |
3325 | print "原始:", str | 3756 | print "原始:", str |
3326 | print "大写:", \upper! | 3757 | print "大写:", \upper! |
3327 | ``` | 3758 | ``` |
3328 | <YueDisplay> | 3759 | <YueDisplay> |
3329 | <pre> | 3760 | <pre> |
3330 | with str = "ä½ å¥½" | 3761 | with str := "ä½ å¥½" |
3331 | print "原始:", str | 3762 | print "原始:", str |
3332 | print "大写:", \upper! | 3763 | print "大写:", \upper! |
3333 | </pre> | 3764 | </pre> |
3334 | </YueDisplay> | 3765 | </YueDisplay> |
3335 | 3766 | ||
3336 | 在withè¯å¥ä¸å¯ä»¥ä½¿ç”¨`[]`访问特殊键。 | 3767 | ä½ å¯ä»¥åœ¨ `with` è¯å¥ä¸ä½¿ç”¨ `[]` 访问特殊键。 |
3337 | 3768 | ||
3338 | ```moonscript | 3769 | ```moonscript |
3339 | with tb | 3770 | with tb |
@@ -3356,6 +3787,19 @@ with tb | |||
3356 | </pre> | 3787 | </pre> |
3357 | </YueDisplay> | 3788 | </YueDisplay> |
3358 | 3789 | ||
3790 | `with?` 是 `with` è¯æ³•的一个增强版本,引入了å˜åœ¨æ€§æ£€æŸ¥ï¼Œç”¨äºŽåœ¨ä¸æ˜¾å¼åˆ¤ç©ºçš„æƒ…况下安全访问å¯èƒ½ä¸º nil 的对象。 | ||
3791 | |||
3792 | ```moonscript | ||
3793 | with? obj | ||
3794 | print obj.name | ||
3795 | ``` | ||
3796 | <YueDisplay> | ||
3797 | <pre> | ||
3798 | with? obj | ||
3799 | print obj.name | ||
3800 | </pre> | ||
3801 | </YueDisplay> | ||
3802 | |||
3359 | ## do è¯å¥ | 3803 | ## do è¯å¥ |
3360 | 3804 | ||
3361 | 当用作è¯å¥æ—¶ï¼Œdoè¯å¥çš„作用就åƒåœ¨Luaä¸å·®ä¸å¤šã€‚ | 3805 | 当用作è¯å¥æ—¶ï¼Œdoè¯å¥çš„作用就åƒåœ¨Luaä¸å·®ä¸å¤šã€‚ |
@@ -3375,7 +3819,7 @@ print var -- 这里是nil | |||
3375 | </pre> | 3819 | </pre> |
3376 | </YueDisplay> | 3820 | </YueDisplay> |
3377 | 3821 | ||
3378 | 月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许您将多行代ç 的处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†doè¯å¥ä»£ç å—的最åŽä¸€ä¸ªè¯å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。 | 3822 | 月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…è®¸ä½ å°†å¤šè¡Œä»£ç 的处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†doè¯å¥ä»£ç å—的最åŽä¸€ä¸ªè¯å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。 |
3379 | 3823 | ||
3380 | ```moonscript | 3824 | ```moonscript |
3381 | counter = do | 3825 | counter = do |
@@ -4334,8 +4778,8 @@ simplified: boolean | |||
4334 | 4778 | ||
4335 | ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\> | 4779 | ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\> |
4336 | 4780 | ||
4337 | 特æ¤å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š | 4781 | 特æ¤å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š |
4338 | 上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸ã€‚ | 4782 | 上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸ã€‚ |
4339 | 本软件是“如æ¤â€æä¾›çš„,没有任何形å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–å…¶ä»–è´£ä»»è´Ÿè´£ï¼Œæ— è®ºè¿™äº›è¿½è´£æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–其它行为ä¸ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。 | 4783 | 本软件是“如æ¤â€æä¾›çš„,没有任何形å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–å…¶ä»–è´£ä»»è´Ÿè´£ï¼Œæ— è®ºè¿™äº›è¿½è´£æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–其它行为ä¸ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。 |
4340 | 4784 | ||
4341 | <CompilerModal /> | 4785 | <CompilerModal /> |
diff --git a/spec/inputs/backcall.yue b/spec/inputs/backcall.yue index 8aadc71..e6b8c21 100644 --- a/spec/inputs/backcall.yue +++ b/spec/inputs/backcall.yue | |||
@@ -13,9 +13,9 @@ do | |||
13 | x > 2 | 13 | x > 2 |
14 | 14 | ||
15 | do | 15 | do |
16 | (data) <- http?.get "ajaxtest" | 16 | data <- http?.get "ajaxtest" |
17 | body[".result"]\html data | 17 | body[".result"]\html data |
18 | (processed) <- http.post "ajaxprocess", data | 18 | processed <- http.post "ajaxprocess", data |
19 | body[".result"]\append processed | 19 | body[".result"]\append processed |
20 | <- setTimeout 1000 | 20 | <- setTimeout 1000 |
21 | print "done" | 21 | print "done" |
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue index 674dfe4..b6250d0 100644 --- a/spec/inputs/destructure.yue +++ b/spec/inputs/destructure.yue | |||
@@ -94,7 +94,7 @@ do | |||
94 | -- | 94 | -- |
95 | 95 | ||
96 | do | 96 | do |
97 | with {a,b} = thing | 97 | with {a,b} := thing |
98 | print a, b | 98 | print a, b |
99 | 99 | ||
100 | 100 | ||
@@ -240,5 +240,43 @@ do | |||
240 | switch tb | 240 | switch tb |
241 | when {c: {<"abc">: meta_field = "def"}, <[[any string]]>: {d: abc = 123}, <'str'>: {e: def = {}}} | 241 | when {c: {<"abc">: meta_field = "def"}, <[[any string]]>: {d: abc = 123}, <'str'>: {e: def = {}}} |
242 | print meta_field, abc, def | 242 | print meta_field, abc, def |
243 | |||
244 | do | ||
245 | clients = ["VIP_Alice", "User_Bob", "User_Clara", "VIP_Eva"] | ||
246 | [vipStart, ...regulars, vipEnd] = clients | ||
247 | print vipStart -- "VIP_Alice" | ||
248 | print regulars -- {"User_Bob", "User_Clara"} | ||
249 | print vipEnd -- "VIP_Eva" | ||
250 | |||
251 | do | ||
252 | setupMeeting = (participants) -> | ||
253 | [chair, ..._, secretary] = participants | ||
254 | print chair, secretary | ||
255 | |||
256 | setupMeeting ["Alice", "Bob", "Charlie", "David"] | ||
257 | -- Output: Alice David | ||
258 | |||
259 | do | ||
260 | getTransactions = -> | ||
261 | { | ||
262 | {id: "T1", amount: 100} | ||
263 | {id: "T2", amount: 200} | ||
264 | {id: "T3", amount: 300} | ||
265 | } | ||
266 | |||
267 | :id, :amount = getTransactions![#] | ||
268 | assert id == "T3" | ||
269 | assert amount == 300 | ||
270 | |||
271 | do | ||
272 | [ | ||
273 | _ | ||
274 | ...middle | ||
275 | _ | ||
276 | ] = tb | ||
277 | |||
278 | do | ||
279 | {a, :abc, b, :def, ...sub, d, e} = tb | ||
280 | |||
243 | nil | 281 | nil |
244 | 282 | ||
diff --git a/spec/inputs/global.yue b/spec/inputs/global.yue index ce1cc15..4e3b8aa 100644 --- a/spec/inputs/global.yue +++ b/spec/inputs/global.yue | |||
@@ -82,3 +82,9 @@ do | |||
82 | FooBar = "pascal case" | 82 | FooBar = "pascal case" |
83 | FOOBAR = "all uppercase" | 83 | FOOBAR = "all uppercase" |
84 | 84 | ||
85 | do | ||
86 | global const class A | ||
87 | global const Flag = 1 | ||
88 | global const const, x, y = "const", 1, 2 | ||
89 | global const math, table | ||
90 | |||
diff --git a/spec/inputs/import.yue b/spec/inputs/import.yue index b8ffc24..8982e6c 100644 --- a/spec/inputs/import.yue +++ b/spec/inputs/import.yue | |||
@@ -139,3 +139,13 @@ do | |||
139 | import "m" as {c: d} | 139 | import "m" as {c: d} |
140 | import "m" as {g, {<close>: i}} | 140 | import "m" as {g, {<close>: i}} |
141 | 141 | ||
142 | do | ||
143 | import require | ||
144 | import string as stringlib | ||
145 | import string.format | ||
146 | import io.read as io_read | ||
147 | |||
148 | type = -> | ||
149 | import type as tp | ||
150 | import 月 as yue | ||
151 | |||
diff --git a/spec/inputs/lists.yue b/spec/inputs/lists.yue index 921cae0..c493b68 100644 --- a/spec/inputs/lists.yue +++ b/spec/inputs/lists.yue | |||
@@ -87,4 +87,51 @@ do | |||
87 | [a, b] = hello | 87 | [a, b] = hello |
88 | [name = "nameless", job = "jobless"] = person | 88 | [name = "nameless", job = "jobless"] = person |
89 | 89 | ||
90 | do | ||
91 | transactions = ["T001", "T002", "T003", "T004", "T005"] | ||
92 | middleTransactions = transactions[2, -2] | ||
93 | print middleTransactions -- => {"T002", "T003", "T004"} | ||
94 | |||
95 | do | ||
96 | logs = | ||
97 | - start: 0, end: 100 | ||
98 | - start: 100, end: 200 | ||
99 | - start: 200, end: 123 | ||
100 | print logs[#].end -- => 123 | ||
101 | |||
102 | do | ||
103 | pendingOrders = ["O001", "O002", "O003", "O004"] | ||
104 | print pendingOrders[# - 1] -- => "O003" | ||
105 | |||
106 | do | ||
107 | getOrders = -> | ||
108 | { | ||
109 | { id: "O1001", status: "pending" } | ||
110 | { id: "O1002", status: "processing" } | ||
111 | { id: "O1003", status: "done" } | ||
112 | } | ||
113 | |||
114 | lastStatus = getOrders()[#].status | ||
115 | assert lastStatus == "done" | ||
116 | |||
117 | do | ||
118 | cloneList1 = (list) -> list[,] | ||
119 | cloneList2 = (list) -> [...list,] | ||
120 | cloneTable = (tb) -> {...tb} | ||
121 | |||
122 | do | ||
123 | print( | ||
124 | globalTB[#] | ||
125 | a.b.c[# - 2] | ||
126 | x?\y?!.z?[# - 3] | ||
127 | ) | ||
128 | |||
129 | do | ||
130 | f = -> | ||
131 | print( | ||
132 | globalTB[#]\end 123 | ||
133 | a.b.c[5,-5][# - 2] | ||
134 | x?\y?!.z?[# - 3]?[, -3] | ||
135 | ) | ||
136 | |||
90 | nil | 137 | nil |
diff --git a/spec/inputs/literals.yue b/spec/inputs/literals.yue index 6b666f0..32cf7e7 100644 --- a/spec/inputs/literals.yue +++ b/spec/inputs/literals.yue | |||
@@ -10,10 +10,19 @@ _ = { | |||
10 | 0xfF2323 | 10 | 0xfF2323 |
11 | 0xabcdef | 11 | 0xabcdef |
12 | 0xABCDEF | 12 | 0xABCDEF |
13 | 0XFB_C4_00 | ||
13 | 0x123p-123 | 14 | 0x123p-123 |
14 | 0xABCP+321 | 15 | 0xABCP+321 |
15 | 0x.1p-111 | 16 | 0x.1p-111 |
16 | 0xA_B_CP-3_2_1 | 17 | 0xA_B_CP-3_2_1 |
18 | 0x0.1E | ||
19 | 0xA23p-4 | ||
20 | 0X1.921FB54442D18P+1 | ||
21 | |||
22 | 0b01 | ||
23 | 0b00_00_10_00 | ||
24 | 0B1111 | ||
25 | 0B00_11_00_10_01 | ||
17 | 26 | ||
18 | .2323 | 27 | .2323 |
19 | .2323e-1 | 28 | .2323e-1 |
diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue index c5b28b3..5df10ca 100644 --- a/spec/inputs/loops.yue +++ b/spec/inputs/loops.yue | |||
@@ -213,3 +213,55 @@ do | |||
213 | do | 213 | do |
214 | until x := func 'a', b do | 214 | until x := func 'a', b do |
215 | print "false expected" | 215 | print "false expected" |
216 | |||
217 | do | ||
218 | index = for i = 1, #tb | ||
219 | break i if tb[i] | ||
220 | |||
221 | f for i = 1, #tb | ||
222 | break i if tb[i] | ||
223 | |||
224 | f for i = 1, #tb | ||
225 | i if tb[i] | ||
226 | |||
227 | i = 1 | ||
228 | ids = while tb[i] | ||
229 | i += 1 | ||
230 | i - 1 | ||
231 | |||
232 | i = 1 | ||
233 | idx = while tb[i] | ||
234 | i += 1 | ||
235 | break i - 1 | ||
236 | |||
237 | f1 = -> | ||
238 | i = 1 | ||
239 | f while tb[i] | ||
240 | i += 1 | ||
241 | i - 1 | ||
242 | |||
243 | i = 1 | ||
244 | f while tb[i] | ||
245 | i += 1 | ||
246 | break i - 1 | ||
247 | |||
248 | list = for item in *items | ||
249 | switch item | ||
250 | when type: "A", :value | ||
251 | if value > 5 | ||
252 | item | ||
253 | |||
254 | do | ||
255 | repeat print 1 until true | ||
256 | |||
257 | x = repeat | ||
258 | a = func! | ||
259 | break a.x | ||
260 | until a.v | ||
261 | |||
262 | items = repeat | ||
263 | item = getItem! | ||
264 | break unless item | ||
265 | item if item.value > 0 | ||
266 | until false | ||
267 | |||
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue index 5d5f1a9..191f09f 100644 --- a/spec/inputs/macro.yue +++ b/spec/inputs/macro.yue | |||
@@ -60,6 +60,11 @@ macro NumAndStr = (num, str) -> | |||
60 | 60 | ||
61 | print $NumAndStr 123, 'xyz' | 61 | print $NumAndStr 123, 'xyz' |
62 | 62 | ||
63 | macro NumAndStr2 = (num`Num, str`SingleString) -> | | ||
64 | [#{num}, #{str}] | ||
65 | |||
66 | print $NumAndStr2 456, 'abc' | ||
67 | |||
63 | $asserts item == nil | 68 | $asserts item == nil |
64 | 69 | ||
65 | $myconfig false | 70 | $myconfig false |
@@ -100,13 +105,14 @@ macro filter = (items, action)-> | |||
100 | $showMacro "filter", "[_ for _ in *#{items} when #{action}]" | 105 | $showMacro "filter", "[_ for _ in *#{items} when #{action}]" |
101 | 106 | ||
102 | macro reduce = (items, def, action)-> | 107 | macro reduce = (items, def, action)-> |
103 | $showMacro "reduce", "if ##{items} == 0 | 108 | $showMacro "reduce", | |
104 | #{def} | 109 | if ##{items} == 0 |
105 | else | 110 | #{def} |
106 | _1 = #{def} | 111 | else |
107 | for _2 in *#{items} | 112 | _1 = #{def} |
108 | _1 = #{action} | 113 | for _2 in *#{items} |
109 | _1" | 114 | _1 = #{action} |
115 | _1 | ||
110 | 116 | ||
111 | macro foreach = (items, action)-> | 117 | macro foreach = (items, action)-> |
112 | $showMacro "foreach", "for _ in *#{items} | 118 | $showMacro "foreach", "for _ in *#{items} |
@@ -154,13 +160,15 @@ macro curry = (...)-> | |||
154 | f = $curry x,y,z,do | 160 | f = $curry x,y,z,do |
155 | print x,y,z | 161 | print x,y,z |
156 | 162 | ||
157 | macro get_inner = (var)-> "do | 163 | macro get_inner = (var)-> | |
158 | a = 1 | 164 | do |
159 | a + 1" | 165 | a = 1 |
166 | a + 1 | ||
160 | 167 | ||
161 | macro get_inner_hygienic = (var)-> "(-> | 168 | macro get_inner_hygienic = (var)-> | |
162 | local a = 1 | 169 | (-> |
163 | a + 1)!" | 170 | local a = 1 |
171 | a + 1)! | ||
164 | 172 | ||
165 | do | 173 | do |
166 | a = 8 | 174 | a = 8 |
@@ -196,6 +204,18 @@ end | |||
196 | 204 | ||
197 | print x | 205 | print x |
198 | 206 | ||
207 | import "yue" | ||
208 | macro lua = (code`YAMLMultiline) -> { | ||
209 | code: yue.loadstring(code)! | ||
210 | type: "lua" | ||
211 | } | ||
212 | |||
213 | $lua | | ||
214 | local function f2(a) | ||
215 | return a + 1 | ||
216 | end | ||
217 | x = x + f2(3) | ||
218 | |||
199 | macro def = (fname, ...)-> | 219 | macro def = (fname, ...)-> |
200 | args = {...} | 220 | args = {...} |
201 | last = table.remove args | 221 | last = table.remove args |
@@ -317,7 +337,13 @@ $chainC( | |||
317 | Destroy! | 337 | Destroy! |
318 | ) | 338 | ) |
319 | 339 | ||
320 | macro tb = -> "{'abc', a:123, <call>:=> 998}" | 340 | macro tb = -> | |
341 | { | ||
342 | 'abc' | ||
343 | a: 123 | ||
344 | <call>: => 998 | ||
345 | } | ||
346 | |||
321 | print $tb[1], $tb.a, ($tb)!, $tb! | 347 | print $tb[1], $tb.a, ($tb)!, $tb! |
322 | 348 | ||
323 | print "current line: #{ $LINE }" | 349 | print "current line: #{ $LINE }" |
diff --git a/spec/inputs/macro_export.yue b/spec/inputs/macro_export.yue index cc7d459..22905b5 100644 --- a/spec/inputs/macro_export.yue +++ b/spec/inputs/macro_export.yue | |||
@@ -8,13 +8,12 @@ export macro config = (debugging = true)-> | |||
8 | "" | 8 | "" |
9 | 9 | ||
10 | export macro showMacro = (name, res)-> | 10 | export macro showMacro = (name, res)-> |
11 | if debugMacro then " | 11 | if debugMacro then | |
12 | do | 12 | do |
13 | txt = #{res} | 13 | txt = #{res} |
14 | print '[macro ' .. #{name} .. ']' | 14 | print '[macro #{name}]' |
15 | print txt | 15 | print txt |
16 | txt | 16 | txt |
17 | " | ||
18 | else | 17 | else |
19 | res | 18 | res |
20 | 19 | ||
@@ -35,14 +34,16 @@ export macro copy = (src, dst, ...)-> | |||
35 | src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_" | 34 | src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_" |
36 | "copy targets can not be _src_ or _dst_" | 35 | "copy targets can not be _src_ or _dst_" |
37 | ) | 36 | ) |
38 | " | 37 | copyFields = table.concat( |
39 | do | 38 | ["_dst_.#{field} = _src_.#{field}" for field in *{...}] |
40 | local _src_, _dst_ | 39 | "\n\t\t\t" |
41 | with _dst_ = #{dst} | 40 | ) |
42 | with _src_ = #{src} | 41 | | |
43 | #{table.concat for field in *{...} do " | 42 | do |
44 | _dst_.#{field} = _src_.#{field} | 43 | local _src_, _dst_ |
45 | "}" | 44 | with _dst_ := #{dst} |
45 | with _src_ := #{src} | ||
46 | #{copyFields} | ||
46 | 47 | ||
47 | export macro enum = (...) -> | 48 | export macro enum = (...) -> |
48 | items = {...} | 49 | items = {...} |
diff --git a/spec/inputs/macro_teal.yue b/spec/inputs/macro_teal.yue index 0cfd862..e51bcd7 100644 --- a/spec/inputs/macro_teal.yue +++ b/spec/inputs/macro_teal.yue | |||
@@ -4,11 +4,16 @@ $ -> | |||
4 | options.target_extension = "tl" | 4 | options.target_extension = "tl" |
5 | package.path ..= ";./spec/lib/?.lua" | 5 | package.path ..= ";./spec/lib/?.lua" |
6 | 6 | ||
7 | macro to_lua = (code)-> | 7 | macro to_lua = (code)-> | |
8 | "require('yue').to_lua(#{code}, reserve_line_number:false, same_module:true)" | 8 | require('yue').to_lua #{code}, |
9 | reserve_line_number: false | ||
10 | same_module: true | ||
9 | 11 | ||
10 | macro trim = (name)-> | 12 | macro trim = (name)-> | |
11 | "if result := #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" | 13 | if result := #{name}\match '[\'"](.*)[\'"]' |
14 | result | ||
15 | else | ||
16 | #{name} | ||
12 | 17 | ||
13 | export macro local = (decl, value = nil)-> | 18 | export macro local = (decl, value = nil)-> |
14 | import "yue" as {options:{:tl_enabled}} | 19 | import "yue" as {options:{:tl_enabled}} |
diff --git a/spec/inputs/macro_todo.yue b/spec/inputs/macro_todo.yue index 752c9cb..c9c8f77 100644 --- a/spec/inputs/macro_todo.yue +++ b/spec/inputs/macro_todo.yue | |||
@@ -5,9 +5,6 @@ export macro todoInner = (module, line, msg)-> | |||
5 | type: "lua" | 5 | type: "lua" |
6 | } | 6 | } |
7 | 7 | ||
8 | export macro todo = (msg)-> | 8 | export macro todo = (msg)-> | |
9 | if msg | 9 | $todoInner $FILE, $LINE#{msg and ", #{msg}" or ""} |
10 | "$todoInner $FILE, $LINE, #{msg}" | ||
11 | else | ||
12 | "$todoInner $FILE, $LINE" | ||
13 | 10 | ||
diff --git a/spec/inputs/props.yue b/spec/inputs/props.yue new file mode 100644 index 0000000..bbb7aae --- /dev/null +++ b/spec/inputs/props.yue | |||
@@ -0,0 +1,61 @@ | |||
1 | class Props | ||
2 | __index: (name): nil => | ||
3 | cls = @.<> | ||
4 | if item := cls.__getter?[name] -- access properties | ||
5 | return item @ | ||
6 | elseif item := rawget cls, name -- access member functions | ||
7 | return item | ||
8 | else | ||
9 | c = cls | ||
10 | while c := c.<> -- recursive to access base classes | ||
11 | if item := c.__getter?[name] | ||
12 | cls.__getter ??= {} | ||
13 | cls.__getter[name] = item -- cache base properties to class | ||
14 | return item @ | ||
15 | elseif item := rawget c, name | ||
16 | rawset cls, name, item -- cache base member to class | ||
17 | return item | ||
18 | |||
19 | __newindex: (name, value) => | ||
20 | cls = @.<> | ||
21 | if item := cls.__setter?[name] -- access properties | ||
22 | item @, value | ||
23 | else | ||
24 | c = cls | ||
25 | while c := c.<> -- recursive to access base classes | ||
26 | if item := c.__setter?[name] | ||
27 | cls.__setter ??= {} | ||
28 | cls.__setter[name] = item -- cache base property to class | ||
29 | item @, value | ||
30 | return | ||
31 | rawset @, name, value -- assign field to self | ||
32 | |||
33 | assignReadOnly = -> error "assigning a readonly property" | ||
34 | |||
35 | prop: (name, props) => | ||
36 | { | ||
37 | :get | ||
38 | :set = assignReadOnly | ||
39 | } = props | ||
40 | if getter := rawget @__base, "__getter" | ||
41 | getter[name] = get | ||
42 | else | ||
43 | rawset @__base, "__getter", [name]: get | ||
44 | if setter := rawget @__base, "__setter" | ||
45 | setter[name] = set | ||
46 | else | ||
47 | rawset @__base, "__setter", [name]: set | ||
48 | |||
49 | class A extends Props | ||
50 | @prop 'x' | ||
51 | get: => @_x + 1000 | ||
52 | set: (v) => @_x = v | ||
53 | new: => | ||
54 | @_x = 0 | ||
55 | |||
56 | class B extends A | ||
57 | @prop 'abc', get: => "hello" | ||
58 | |||
59 | b = B! | ||
60 | b.x = 999 | ||
61 | print b.x, b.abc | ||
diff --git a/spec/inputs/string.yue b/spec/inputs/string.yue index f91383e..1f0fba8 100644 --- a/spec/inputs/string.yue +++ b/spec/inputs/string.yue | |||
@@ -74,3 +74,76 @@ _ = "hello" | |||
74 | something"hello"\world! | 74 | something"hello"\world! |
75 | something "hello"\world! | 75 | something "hello"\world! |
76 | 76 | ||
77 | do | ||
78 | str = | | ||
79 | key: value | ||
80 | str = | | ||
81 | config: | ||
82 | enabled: true | ||
83 | level: 5 | ||
84 | str = | | ||
85 | header: start | ||
86 | |||
87 | footer: end | ||
88 | str = | | ||
89 | name: #{username} | ||
90 | str = | | ||
91 | count: #{total} items | ||
92 | str = | | ||
93 | user: #{name} | ||
94 | id: #{id} | ||
95 | str = | | ||
96 | path: "C:\\Program Files\\App" | ||
97 | desc: 'single "quote" test' | ||
98 | str = | | ||
99 | key: value | ||
100 | next: 123 | ||
101 | str = | | ||
102 | list: | ||
103 | - "one" | ||
104 | - "two" | ||
105 | str = | | ||
106 | -- comment | ||
107 | content text | ||
108 | -- comment | ||
109 | str = | | ||
110 | #{1 + 2} | ||
111 | #{2 + 3} | ||
112 | #{"a" .. "b"} | ||
113 | obj = | ||
114 | settings: | | ||
115 | mode: #{mode} | ||
116 | flags: | ||
117 | - #{flag1} | ||
118 | - default | ||
119 | fn = -> | | ||
120 | Hello | ||
121 | name: #{userName} | ||
122 | str = | | ||
123 | result: | ||
124 | status: #{if ok then "pass" else "fail"} | ||
125 | code: #{code} | ||
126 | summary = | | ||
127 | date: #{os.date()} | ||
128 | values: | ||
129 | - | ||
130 | a: #{aVal} | ||
131 | b: #{bVal or defaultB} | ||
132 | msg = send | | ||
133 | Hello, #{user}! | ||
134 | Today is #{os.date("%A")}. | ||
135 | desc = do | ||
136 | prefix = "Result" | ||
137 | | | ||
138 | #{prefix}: | ||
139 | value: #{compute!} | ||
140 | (| | ||
141 | 1 | ||
142 | 2 | ||
143 | 3 | ||
144 | |||
145 | |||
146 | export yaml = | | ||
147 | version: #{ver} | ||
148 | ok: true | ||
149 | |||
diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue index 49d47f3..2b0669c 100644 --- a/spec/inputs/switch.yue +++ b/spec/inputs/switch.yue | |||
@@ -165,5 +165,128 @@ do | |||
165 | print item | 165 | print item |
166 | when [a = 1, b = "abc"] | 166 | when [a = 1, b = "abc"] |
167 | print a, b | 167 | print a, b |
168 | nil | ||
169 | 168 | ||
169 | do | ||
170 | switch tb | ||
171 | when [1, 2, 3] | ||
172 | print "1, 2, 3" | ||
173 | when [1, b, 3] | ||
174 | print "1, #{b}, 3" | ||
175 | when [1, 2, b = 3] | ||
176 | print "1, 2, #{b}" | ||
177 | |||
178 | do | ||
179 | switch tb | ||
180 | when success: true, :result | ||
181 | print "success", result | ||
182 | when success: false | ||
183 | print "failed", result | ||
184 | else | ||
185 | print "invalid" | ||
186 | |||
187 | do | ||
188 | switch tb | ||
189 | when {type: "success", :content} | ||
190 | print "success", content | ||
191 | when {type: "error", :content} | ||
192 | print "failed", content | ||
193 | else | ||
194 | print "invalid" | ||
195 | |||
196 | do | ||
197 | switch tb | ||
198 | when [ | ||
199 | {a: 1, b: 2} | ||
200 | {a: 3, b: 4} | ||
201 | {a: 5, b: 6} | ||
202 | fourth | ||
203 | ] | ||
204 | print "matched", fourth | ||
205 | |||
206 | switch tb | ||
207 | when [ | ||
208 | {c: 1, d: 2} | ||
209 | {c: 3, d: 4} | ||
210 | {c: 5, d: 6} | ||
211 | ] | ||
212 | print "OK" | ||
213 | when [ | ||
214 | _ | ||
215 | _ | ||
216 | {a: 1, b: 2} | ||
217 | {a: 3, b: 4} | ||
218 | {a: 5, b: 6} | ||
219 | sixth | ||
220 | ] | ||
221 | print "matched", sixth | ||
222 | |||
223 | do | ||
224 | switch v := "hello" | ||
225 | when "hello" | ||
226 | print "matched hello" | ||
227 | else | ||
228 | print "not matched" | ||
229 | -- output: matched hello | ||
230 | |||
231 | do | ||
232 | f = -> "ok" | ||
233 | switch val := f! | ||
234 | when "ok" | ||
235 | print "it's ok" | ||
236 | -- output: it's ok | ||
237 | |||
238 | |||
239 | do | ||
240 | g = -> 42 | ||
241 | switch result := g! | ||
242 | when 1, 2 | ||
243 | print "small" | ||
244 | when 42 | ||
245 | print "life universe everything" | ||
246 | else | ||
247 | print "other #{result}" | ||
248 | -- output: life universe everything | ||
249 | |||
250 | do | ||
251 | check = -> | ||
252 | if true | ||
253 | "yes" | ||
254 | else | ||
255 | "no" | ||
256 | |||
257 | switch x := check! | ||
258 | when "yes" | ||
259 | print "affirmative" | ||
260 | else | ||
261 | print "negative" | ||
262 | -- output: affirmative | ||
263 | |||
264 | do | ||
265 | t = (): tb -> | ||
266 | tb = {a: 1} | ||
267 | tb.a = 2 | ||
268 | |||
269 | switch data := t! | ||
270 | when {a: 2} | ||
271 | print "matched" | ||
272 | else | ||
273 | print "not matched" | ||
274 | |||
275 | do | ||
276 | clientData = ["Meta", "CUST_1001", "CHK123"] | ||
277 | switch clientData | ||
278 | when [...metadata, customerId, checksum] | ||
279 | print metadata -- {"Meta"} | ||
280 | print customerId -- "CUST_1001" | ||
281 | print checksum -- "CHK123" | ||
282 | |||
283 | do | ||
284 | handlePath = (segments) -> | ||
285 | switch segments | ||
286 | when [..._, resource, action] | ||
287 | print "Resource:", resource | ||
288 | print "Action:", action | ||
289 | |||
290 | handlePath ["admin", "logs", "view"] | ||
291 | |||
292 | nil | ||
diff --git a/spec/inputs/tables.yue b/spec/inputs/tables.yue index 0de8a8c..702e04a 100644 --- a/spec/inputs/tables.yue +++ b/spec/inputs/tables.yue | |||
@@ -245,6 +245,24 @@ menus = | |||
245 | click: -> | 245 | click: -> |
246 | } | 246 | } |
247 | 247 | ||
248 | _ = | ||
249 | boolean: | ||
250 | - true | ||
251 | - false | ||
252 | float: | ||
253 | - 3.14 | ||
254 | - -6.8523015e+5 | ||
255 | int: | ||
256 | - 123 | ||
257 | - -0b1010_0111_0100_1010_1110 | ||
258 | null: | ||
259 | nodeName: 'node' | ||
260 | parent: nil | ||
261 | string: | ||
262 | - 'Hello world' | ||
263 | - "newline | ||
264 | newline2" | ||
265 | |||
248 | tb = {...other} | 266 | tb = {...other} |
249 | 267 | ||
250 | tbMix = { | 268 | tbMix = { |
diff --git a/spec/inputs/try_catch.yue b/spec/inputs/try_catch.yue index 4e05bc6..6c29a52 100644 --- a/spec/inputs/try_catch.yue +++ b/spec/inputs/try_catch.yue | |||
@@ -62,6 +62,126 @@ f = -> | |||
62 | do | 62 | do |
63 | <- x | 63 | <- x |
64 | local tb, a, b, c | 64 | local tb, a, b, c |
65 | f = -> try tb.f a, b, c | 65 | f1 = -> try tb.f a, b, c |
66 | |||
67 | do | ||
68 | f1 = -> do | ||
69 | ok, ... = try func! | ||
70 | ... | ||
71 | |||
72 | do | ||
73 | local func | ||
74 | a, b, c = try? func! | ||
75 | |||
76 | do | ||
77 | a, b, c = try? func! | ||
78 | |||
79 | do | ||
80 | a = (try? func!) ?? "default" | ||
81 | |||
82 | do | ||
83 | f try? func! | ||
84 | |||
85 | do | ||
86 | f try? | ||
87 | print 123 | ||
88 | func! | ||
89 | catch e | ||
90 | print e | ||
91 | e | ||
66 | 92 | ||
67 | nil | 93 | nil |
94 | |||
95 | do | ||
96 | try | ||
97 | func 1, 2, 3 | ||
98 | catch err | ||
99 | print err | ||
100 | |||
101 | try func 1, 2, 3 | ||
102 | catch err | ||
103 | print err | ||
104 | |||
105 | try | ||
106 | print "trying" | ||
107 | func 1, 2, 3 | ||
108 | |||
109 | do | ||
110 | success, result = try | ||
111 | func 1, 2, 3 | ||
112 | catch err | ||
113 | print err | ||
114 | |||
115 | success, result = try func 1, 2, 3 | ||
116 | |||
117 | tb = {} | ||
118 | |||
119 | try tb.func | ||
120 | try tb.func! | ||
121 | try tb.func() | ||
122 | try (tb.func!) | ||
123 | try (tb\func(1, 2, 3)) | ||
124 | |||
125 | try tb.func 1 | ||
126 | try tb.func(1) | ||
127 | |||
128 | if (try func 1 | ||
129 | catch err | ||
130 | print err) | ||
131 | print "OK" | ||
132 | |||
133 | if try (func 1) | ||
134 | catch err | ||
135 | print err | ||
136 | print "OK" | ||
137 | |||
138 | do | ||
139 | if success, result := try func "abc", 123 | ||
140 | print result | ||
141 | |||
142 | success, result = try func "abc", 123 | ||
143 | catch err | ||
144 | print err | ||
145 | |||
146 | print result if success, result := try func "abc", 123 | ||
147 | catch err | ||
148 | print err | ||
149 | |||
150 | do | ||
151 | try | ||
152 | func 1, 2, 3 | ||
153 | |||
154 | try func 1, 2, 3 | ||
155 | |||
156 | do | ||
157 | <- x | ||
158 | local tb, a, b, c | ||
159 | f1 = -> try tb.f a, b, c | ||
160 | |||
161 | do | ||
162 | f1 = -> do | ||
163 | ok, ... = try func! | ||
164 | ... | ||
165 | |||
166 | do | ||
167 | local func | ||
168 | a, b, c = try? func! | ||
169 | |||
170 | do | ||
171 | a, b, c = try? func! | ||
172 | |||
173 | do | ||
174 | a = (try? func!) ?? "default" | ||
175 | |||
176 | do | ||
177 | f try? func! | ||
178 | |||
179 | do | ||
180 | f try? | ||
181 | print 123 | ||
182 | func! | ||
183 | catch e | ||
184 | print e | ||
185 | e | ||
186 | |||
187 | nil | ||
diff --git a/spec/inputs/unicode/destructure.yue b/spec/inputs/unicode/destructure.yue index 3c3a369..a5ffd5d 100644 --- a/spec/inputs/unicode/destructure.yue +++ b/spec/inputs/unicode/destructure.yue | |||
@@ -84,7 +84,7 @@ do | |||
84 | -- | 84 | -- |
85 | 85 | ||
86 | do | 86 | do |
87 | with {å…ƒç´ a,å…ƒç´ b} = 东西 | 87 | with {å…ƒç´ a,å…ƒç´ b} := 东西 |
88 | æ‰“å° å…ƒç´ a, å…ƒç´ b | 88 | æ‰“å° å…ƒç´ a, å…ƒç´ b |
89 | 89 | ||
90 | 90 | ||
diff --git a/spec/inputs/unicode/macro_export.yue b/spec/inputs/unicode/macro_export.yue index 3c9a942..56571cd 100644 --- a/spec/inputs/unicode/macro_export.yue +++ b/spec/inputs/unicode/macro_export.yue | |||
@@ -37,8 +37,8 @@ export macro å¤åˆ¶ = (æº, ç›®æ ‡, ...)-> | |||
37 | " | 37 | " |
38 | do | 38 | do |
39 | local _æº_, _ç›®æ ‡_ | 39 | local _æº_, _ç›®æ ‡_ |
40 | with _ç›®æ ‡_ = #{ç›®æ ‡} | 40 | with _ç›®æ ‡_ := #{ç›®æ ‡} |
41 | with _æº_ = #{æº} | 41 | with _æº_ := #{æº} |
42 | #{table.concat for å—æ®µ in *{...} do " | 42 | #{table.concat for å—æ®µ in *{...} do " |
43 | _ç›®æ ‡_.#{å—æ®µ} = _æº_.#{å—æ®µ} | 43 | _ç›®æ ‡_.#{å—æ®µ} = _æº_.#{å—æ®µ} |
44 | "}" | 44 | "}" |
diff --git a/spec/inputs/unicode/with.yue b/spec/inputs/unicode/with.yue index ecbfdab..3c15add 100644 --- a/spec/inputs/unicode/with.yue +++ b/spec/inputs/unicode/with.yue | |||
@@ -45,19 +45,19 @@ do | |||
45 | with å˜é‡a | 45 | with å˜é‡a |
46 | æ‰“å° .世界 | 46 | æ‰“å° .世界 |
47 | 47 | ||
48 | æ¨¡å— = with _æ¨¡å— = {} | 48 | æ¨¡å— = with _æ¨¡å— := {} |
49 | .事物 = "ä½ å¥½" | 49 | .事物 = "ä½ å¥½" |
50 | 50 | ||
51 | with å˜é‡a, å˜é‡b = 东西, 布 | 51 | with å˜é‡a, å˜é‡b := 东西, 布 |
52 | æ‰“å° .世界 | 52 | æ‰“å° .世界 |
53 | 53 | ||
54 | å˜é‡x = with å˜é‡a, å˜é‡b = 1, 2 | 54 | å˜é‡x = with å˜é‡a, å˜é‡b := 1, 2 |
55 | æ‰“å° å˜é‡a + å˜é‡b | 55 | æ‰“å° å˜é‡a + å˜é‡b |
56 | 56 | ||
57 | æ‰“å° with å˜é‡a, å˜é‡b = 1, 2 | 57 | æ‰“å° with å˜é‡a, å˜é‡b := 1, 2 |
58 | æ‰“å° å˜é‡a + å˜é‡b | 58 | æ‰“å° å˜é‡a + å˜é‡b |
59 | 59 | ||
60 | p = with ä½ å¥½!.å—æ®µx, 世界!.å—æ®µy = 1, 2 | 60 | p = with ä½ å¥½!.å—æ®µx, 世界!.å—æ®µy := 1, 2 |
61 | æ‰“å° å˜é‡a + å˜é‡b | 61 | æ‰“å° å˜é‡a + å˜é‡b |
62 | 62 | ||
63 | -- | 63 | -- |
@@ -68,16 +68,16 @@ do | |||
68 | å˜é‡x\大写! | 68 | å˜é‡x\大写! |
69 | 69 | ||
70 | do | 70 | do |
71 | with å˜é‡k = "ä¹”" | 71 | with å˜é‡k := "ä¹”" |
72 | æ‰“å° \大写! | 72 | æ‰“å° \大写! |
73 | 73 | ||
74 | do | 74 | do |
75 | with å˜é‡a,å˜é‡b,å˜é‡c = "", "", "" | 75 | with å˜é‡a,å˜é‡b,å˜é‡c := "", "", "" |
76 | æ‰“å° \大写! | 76 | æ‰“å° \大写! |
77 | 77 | ||
78 | do | 78 | do |
79 | å˜é‡a = "床铺" | 79 | å˜é‡a = "床铺" |
80 | with å˜é‡a,å˜é‡b,å˜é‡c = "", "", "" | 80 | with å˜é‡a,å˜é‡b,å˜é‡c := "", "", "" |
81 | æ‰“å° \大写! | 81 | æ‰“å° \大写! |
82 | 82 | ||
83 | do | 83 | do |
@@ -85,7 +85,7 @@ do | |||
85 | æ‰“å° \大写! | 85 | æ‰“å° \大写! |
86 | 86 | ||
87 | do | 87 | do |
88 | with å˜é‡k.å˜é‡j = "ä¹”" | 88 | with å˜é‡k.å˜é‡j := "ä¹”" |
89 | æ‰“å° \大写! | 89 | æ‰“å° \大写! |
90 | 90 | ||
91 | do | 91 | do |
@@ -96,7 +96,7 @@ do | |||
96 | 96 | ||
97 | do | 97 | do |
98 | with å˜é‡a | 98 | with å˜é‡a |
99 | with .b = 2 | 99 | with .b := 2 |
100 | æ‰“å° .c | 100 | æ‰“å° .c |
101 | 101 | ||
102 | do | 102 | do |
@@ -131,12 +131,12 @@ do | |||
131 | 131 | ||
132 | do | 132 | do |
133 | global 掩ç | 133 | global 掩ç |
134 | with? 掩ç = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 | 134 | with? 掩ç := 实心矩形 宽: w, 高: h, 颜色: 0x66000000 |
135 | .触摸å¯ç”¨ = true | 135 | .触摸å¯ç”¨ = true |
136 | .åžå™¬è§¦æ‘¸ = true | 136 | .åžå™¬è§¦æ‘¸ = true |
137 | 137 | ||
138 | do | 138 | do |
139 | with? 掩ç = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 | 139 | with? 掩ç := 实心矩形 宽: w, 高: h, 颜色: 0x66000000 |
140 | .触摸å¯ç”¨ = true | 140 | .触摸å¯ç”¨ = true |
141 | .åžå™¬è§¦æ‘¸ = true | 141 | .åžå™¬è§¦æ‘¸ = true |
142 | 142 | ||
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue index 19b7be1..2256833 100644 --- a/spec/inputs/with.yue +++ b/spec/inputs/with.yue | |||
@@ -48,21 +48,21 @@ do | |||
48 | with a -- only one value allowed | 48 | with a -- only one value allowed |
49 | print .world | 49 | print .world |
50 | 50 | ||
51 | mod = with _M = {} | 51 | mod = with _M := {} |
52 | .Thing = "hi" | 52 | .Thing = "hi" |
53 | 53 | ||
54 | -- operate on a only | 54 | -- operate on a only |
55 | with a, b = something, pooh | 55 | with a, b := something, pooh |
56 | print .world | 56 | print .world |
57 | 57 | ||
58 | x = with a, b = 1, 2 | 58 | x = with a, b := 1, 2 |
59 | print a + b | 59 | print a + b |
60 | 60 | ||
61 | print with a, b = 1, 2 | 61 | print with a, b := 1, 2 |
62 | print a + b | 62 | print a + b |
63 | 63 | ||
64 | -- assignment lhs must be evaluated in the order they appear | 64 | -- assignment lhs must be evaluated in the order they appear |
65 | p = with hello!.x, world!.y = 1, 2 | 65 | p = with hello!.x, world!.y := 1, 2 |
66 | print a + b | 66 | print a + b |
67 | 67 | ||
68 | -- | 68 | -- |
@@ -73,16 +73,16 @@ do | |||
73 | x\upper! | 73 | x\upper! |
74 | 74 | ||
75 | do | 75 | do |
76 | with k = "jo" | 76 | with k := "jo" |
77 | print \upper! | 77 | print \upper! |
78 | 78 | ||
79 | do | 79 | do |
80 | with a,b,c = "", "", "" | 80 | with a,b,c := "", "", "" |
81 | print \upper! | 81 | print \upper! |
82 | 82 | ||
83 | do | 83 | do |
84 | a = "bunk" | 84 | a = "bunk" |
85 | with a,b,c = "", "", "" | 85 | with a,b,c := "", "", "" |
86 | print \upper! | 86 | print \upper! |
87 | 87 | ||
88 | do | 88 | do |
@@ -90,7 +90,7 @@ do | |||
90 | print \upper! | 90 | print \upper! |
91 | 91 | ||
92 | do | 92 | do |
93 | with k.j = "jo" | 93 | with k.j := "jo" |
94 | print \upper! | 94 | print \upper! |
95 | 95 | ||
96 | do | 96 | do |
@@ -103,7 +103,7 @@ do | |||
103 | do | 103 | do |
104 | with a | 104 | with a |
105 | -- nested `with`s with assignments should change the scope correctly | 105 | -- nested `with`s with assignments should change the scope correctly |
106 | with .b = 2 | 106 | with .b := 2 |
107 | print .c | 107 | print .c |
108 | 108 | ||
109 | do | 109 | do |
@@ -138,12 +138,12 @@ do | |||
138 | 138 | ||
139 | do | 139 | do |
140 | global mask | 140 | global mask |
141 | with? mask = SolidRect width: w, height: h, color: 0x66000000 | 141 | with? mask := SolidRect width: w, height: h, color: 0x66000000 |
142 | .touchEnabled = true | 142 | .touchEnabled = true |
143 | .swallowTouches = true | 143 | .swallowTouches = true |
144 | 144 | ||
145 | do | 145 | do |
146 | with? mask = SolidRect width: w, height: h, color: 0x66000000 | 146 | with? mask := SolidRect width: w, height: h, color: 0x66000000 |
147 | .touchEnabled = true | 147 | .touchEnabled = true |
148 | .swallowTouches = true | 148 | .swallowTouches = true |
149 | 149 | ||
@@ -152,4 +152,22 @@ do | |||
152 | return with {} | 152 | return with {} |
153 | return [123] | 153 | return [123] |
154 | 154 | ||
155 | do | ||
156 | f with item | ||
157 | if .id > 0 | ||
158 | break .content | ||
159 | |||
160 | a = with tb | ||
161 | if .v | ||
162 | break .a | ||
163 | |||
164 | a = while true | ||
165 | break with? tb | ||
166 | break 1 | ||
167 | |||
168 | do | ||
169 | a = for i = 1, 100 | ||
170 | with? x := tb[i] | ||
171 | break x if .id := 1 | ||
172 | |||
155 | nil | 173 | nil |
diff --git a/spec/outputs/5.1/attrib.lua b/spec/outputs/5.1/attrib.lua index a156e84..bda24bc 100644 --- a/spec/outputs/5.1/attrib.lua +++ b/spec/outputs/5.1/attrib.lua | |||
@@ -136,9 +136,11 @@ do | |||
136 | end | 136 | end |
137 | local b | 137 | local b |
138 | if not false then | 138 | if not false then |
139 | if x then | 139 | b = ((function() |
140 | b = 1 | 140 | if x then |
141 | end | 141 | return 1 |
142 | end | ||
143 | end)()) | ||
142 | end | 144 | end |
143 | local _close_0 | 145 | local _close_0 |
144 | if (function() | 146 | if (function() |
@@ -164,10 +166,12 @@ do | |||
164 | end)(pcall(function() | 166 | end)(pcall(function() |
165 | local c | 167 | local c |
166 | if true then | 168 | if true then |
167 | local _exp_0 = x | 169 | c = ((function() |
168 | if "abc" == _exp_0 then | 170 | local _exp_0 = x |
169 | c = 998 | 171 | if "abc" == _exp_0 then |
170 | end | 172 | return 998 |
173 | end | ||
174 | end)()) | ||
171 | end | 175 | end |
172 | local d | 176 | local d |
173 | if (function() | 177 | if (function() |
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua index 57b19be..e4f2871 100644 --- a/spec/outputs/5.1/loops.lua +++ b/spec/outputs/5.1/loops.lua | |||
@@ -60,8 +60,8 @@ do | |||
60 | local y = hello[_index_0] | 60 | local y = hello[_index_0] |
61 | if y % 2 == 0 then | 61 | if y % 2 == 0 then |
62 | _accum_0[_len_0] = y | 62 | _accum_0[_len_0] = y |
63 | _len_0 = _len_0 + 1 | ||
63 | end | 64 | end |
64 | _len_0 = _len_0 + 1 | ||
65 | end | 65 | end |
66 | x = _accum_0 | 66 | x = _accum_0 |
67 | end | 67 | end |
@@ -132,13 +132,11 @@ do | |||
132 | end | 132 | end |
133 | do | 133 | do |
134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
135 | local _len_0 = 1 | ||
136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
138 | local thing = _list_2[_index_0] | 137 | local thing = _list_2[_index_0] |
139 | y = "hello" | 138 | y = "hello" |
140 | break | 139 | break |
141 | _len_0 = _len_0 + 1 | ||
142 | end | 140 | end |
143 | x = _accum_0 | 141 | x = _accum_0 |
144 | end | 142 | end |
@@ -489,3 +487,131 @@ do | |||
489 | end | 487 | end |
490 | until false | 488 | until false |
491 | end | 489 | end |
490 | local _anon_func_0 = function(i, tb) | ||
491 | local _accum_0 = { } | ||
492 | local _len_0 = 1 | ||
493 | while tb[i] do | ||
494 | i = i + 1 | ||
495 | _accum_0[_len_0] = i - 1 | ||
496 | _len_0 = _len_0 + 1 | ||
497 | end | ||
498 | return _accum_0 | ||
499 | end | ||
500 | do | ||
501 | local index | ||
502 | do | ||
503 | local _accum_0 | ||
504 | for i = 1, #tb do | ||
505 | if tb[i] then | ||
506 | _accum_0 = i | ||
507 | break | ||
508 | end | ||
509 | end | ||
510 | index = _accum_0 | ||
511 | end | ||
512 | f((function() | ||
513 | local _accum_0 | ||
514 | for i = 1, #tb do | ||
515 | if tb[i] then | ||
516 | _accum_0 = i | ||
517 | break | ||
518 | end | ||
519 | end | ||
520 | return _accum_0 | ||
521 | end)()) | ||
522 | f((function() | ||
523 | local _accum_0 = { } | ||
524 | local _len_0 = 1 | ||
525 | for i = 1, #tb do | ||
526 | if tb[i] then | ||
527 | _accum_0[_len_0] = i | ||
528 | _len_0 = _len_0 + 1 | ||
529 | end | ||
530 | end | ||
531 | return _accum_0 | ||
532 | end)()) | ||
533 | i = 1 | ||
534 | local ids | ||
535 | do | ||
536 | local _accum_0 = { } | ||
537 | local _len_0 = 1 | ||
538 | while tb[i] do | ||
539 | i = i + 1 | ||
540 | _accum_0[_len_0] = i - 1 | ||
541 | _len_0 = _len_0 + 1 | ||
542 | end | ||
543 | ids = _accum_0 | ||
544 | end | ||
545 | i = 1 | ||
546 | local idx | ||
547 | do | ||
548 | local _accum_0 | ||
549 | while tb[i] do | ||
550 | i = i + 1 | ||
551 | _accum_0 = i - 1 | ||
552 | break | ||
553 | end | ||
554 | idx = _accum_0 | ||
555 | end | ||
556 | local f1 | ||
557 | f1 = function() | ||
558 | i = 1 | ||
559 | return f(_anon_func_0(i, tb)) | ||
560 | end | ||
561 | i = 1 | ||
562 | f((function() | ||
563 | local _accum_0 | ||
564 | while tb[i] do | ||
565 | i = i + 1 | ||
566 | _accum_0 = i - 1 | ||
567 | break | ||
568 | end | ||
569 | return _accum_0 | ||
570 | end)()) | ||
571 | local _accum_0 = { } | ||
572 | local _len_0 = 1 | ||
573 | local _list_3 = items | ||
574 | for _index_0 = 1, #_list_3 do | ||
575 | local item = _list_3[_index_0] | ||
576 | local _type_0 = type(item) | ||
577 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
578 | if _tab_0 then | ||
579 | local value = item.value | ||
580 | if "A" == item.type and value ~= nil then | ||
581 | if value > 5 then | ||
582 | _accum_0[_len_0] = item | ||
583 | _len_0 = _len_0 + 1 | ||
584 | end | ||
585 | end | ||
586 | end | ||
587 | end | ||
588 | list = _accum_0 | ||
589 | end | ||
590 | do | ||
591 | repeat | ||
592 | print(1) | ||
593 | until true | ||
594 | do | ||
595 | local _accum_0 | ||
596 | repeat | ||
597 | a = func() | ||
598 | _accum_0 = a.x | ||
599 | break | ||
600 | until a.v | ||
601 | x = _accum_0 | ||
602 | end | ||
603 | local items | ||
604 | local _accum_0 = { } | ||
605 | local _len_0 = 1 | ||
606 | repeat | ||
607 | local item = getItem() | ||
608 | if not item then | ||
609 | break | ||
610 | end | ||
611 | if item.value > 0 then | ||
612 | _accum_0[_len_0] = item | ||
613 | _len_0 = _len_0 + 1 | ||
614 | end | ||
615 | until false | ||
616 | items = _accum_0 | ||
617 | end | ||
diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua index d4c80c1..d2b58bc 100644 --- a/spec/outputs/5.1/try_catch.lua +++ b/spec/outputs/5.1/try_catch.lua | |||
@@ -8,10 +8,10 @@ local _anon_func_2 = function(tb) | |||
8 | return tb.func() | 8 | return tb.func() |
9 | end | 9 | end |
10 | local _anon_func_3 = function(tb) | 10 | local _anon_func_3 = function(tb) |
11 | return tb.func() | 11 | return (tb.func()) |
12 | end | 12 | end |
13 | local _anon_func_4 = function(tb) | 13 | local _anon_func_4 = function(tb) |
14 | return tb:func(1, 2, 3) | 14 | return (tb:func(1, 2, 3)) |
15 | end | 15 | end |
16 | local _anon_func_5 = function(tb) | 16 | local _anon_func_5 = function(tb) |
17 | return tb.func(1) | 17 | return tb.func(1) |
@@ -22,6 +22,43 @@ end | |||
22 | local _anon_func_7 = function(a, b, c, tb) | 22 | local _anon_func_7 = function(a, b, c, tb) |
23 | return tb.f(a, b, c) | 23 | return tb.f(a, b, c) |
24 | end | 24 | end |
25 | local _anon_func_8 = function(_arg_0, ...) | ||
26 | local ok = _arg_0 | ||
27 | return ... | ||
28 | end | ||
29 | local _anon_func_10 = function(_arg_0, ...) | ||
30 | local _ok_0 = _arg_0 | ||
31 | if _ok_0 then | ||
32 | return ... | ||
33 | end | ||
34 | end | ||
35 | local _anon_func_9 = function(func, pcall) | ||
36 | return _anon_func_10(pcall(func)) | ||
37 | end | ||
38 | local _anon_func_12 = function(_arg_0, ...) | ||
39 | local _ok_0 = _arg_0 | ||
40 | if _ok_0 then | ||
41 | return ... | ||
42 | end | ||
43 | end | ||
44 | local _anon_func_11 = function(func, pcall) | ||
45 | return _anon_func_12(pcall(func)) | ||
46 | end | ||
47 | local _anon_func_14 = function(_arg_0, ...) | ||
48 | local _ok_0 = _arg_0 | ||
49 | if _ok_0 then | ||
50 | return ... | ||
51 | end | ||
52 | end | ||
53 | local _anon_func_13 = function(func, print, xpcall) | ||
54 | return _anon_func_14(xpcall(function() | ||
55 | print(123) | ||
56 | return func() | ||
57 | end, function(e) | ||
58 | print(e) | ||
59 | return e | ||
60 | end)) | ||
61 | end | ||
25 | local f | 62 | local f |
26 | f = function() | 63 | f = function() |
27 | xpcall(function() | 64 | xpcall(function() |
@@ -64,7 +101,7 @@ f = function() | |||
64 | print("OK") | 101 | print("OK") |
65 | end | 102 | end |
66 | if xpcall(function() | 103 | if xpcall(function() |
67 | return func(1) | 104 | return (func(1)) |
68 | end, function(err) | 105 | end, function(err) |
69 | return print(err) | 106 | return print(err) |
70 | end) then | 107 | end) then |
@@ -104,10 +141,236 @@ f = function() | |||
104 | do | 141 | do |
105 | x(function() | 142 | x(function() |
106 | local tb, a, b, c | 143 | local tb, a, b, c |
107 | f = function() | 144 | local f1 |
145 | f1 = function() | ||
108 | return pcall(_anon_func_7, a, b, c, tb) | 146 | return pcall(_anon_func_7, a, b, c, tb) |
109 | end | 147 | end |
110 | end) | 148 | end) |
111 | end | 149 | end |
150 | do | ||
151 | local f1 | ||
152 | f1 = function() | ||
153 | do | ||
154 | return _anon_func_8(pcall(function() | ||
155 | return func() | ||
156 | end)) | ||
157 | end | ||
158 | end | ||
159 | end | ||
160 | do | ||
161 | local func | ||
162 | local a, b, c | ||
163 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) | ||
164 | if _ok_0 then | ||
165 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
166 | end | ||
167 | end | ||
168 | do | ||
169 | local a, b, c | ||
170 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
171 | return func() | ||
172 | end) | ||
173 | if _ok_0 then | ||
174 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
175 | end | ||
176 | end | ||
177 | do | ||
178 | local a | ||
179 | local _exp_0 = (_anon_func_9(func, pcall)) | ||
180 | if _exp_0 ~= nil then | ||
181 | a = _exp_0 | ||
182 | else | ||
183 | a = "default" | ||
184 | end | ||
185 | end | ||
186 | do | ||
187 | f(_anon_func_11(func, pcall)) | ||
188 | end | ||
189 | do | ||
190 | f(_anon_func_13(func, print, xpcall)) | ||
191 | end | ||
112 | return nil | 192 | return nil |
113 | end | 193 | end |
194 | local _anon_func_15 = function(a, b, c, tb) | ||
195 | return tb.f(a, b, c) | ||
196 | end | ||
197 | local _anon_func_16 = function(_arg_0, ...) | ||
198 | local ok = _arg_0 | ||
199 | return ... | ||
200 | end | ||
201 | do | ||
202 | xpcall(function() | ||
203 | return func(1, 2, 3) | ||
204 | end, function(err) | ||
205 | return print(err) | ||
206 | end) | ||
207 | xpcall(function() | ||
208 | return func(1, 2, 3) | ||
209 | end, function(err) | ||
210 | return print(err) | ||
211 | end) | ||
212 | pcall(function() | ||
213 | print("trying") | ||
214 | return func(1, 2, 3) | ||
215 | end) | ||
216 | do | ||
217 | local success, result = xpcall(function() | ||
218 | return func(1, 2, 3) | ||
219 | end, function(err) | ||
220 | return print(err) | ||
221 | end) | ||
222 | success, result = pcall(function() | ||
223 | return func(1, 2, 3) | ||
224 | end) | ||
225 | end | ||
226 | local tb = { } | ||
227 | pcall(function() | ||
228 | return tb.func | ||
229 | end) | ||
230 | pcall(function() | ||
231 | return tb.func() | ||
232 | end) | ||
233 | pcall(function() | ||
234 | return tb.func() | ||
235 | end) | ||
236 | pcall(function() | ||
237 | return (tb.func()) | ||
238 | end) | ||
239 | pcall(function() | ||
240 | return (tb:func(1, 2, 3)) | ||
241 | end) | ||
242 | pcall(function() | ||
243 | return tb.func(1) | ||
244 | end) | ||
245 | pcall(function() | ||
246 | return tb.func(1) | ||
247 | end) | ||
248 | if (xpcall(function() | ||
249 | return func(1) | ||
250 | end, function(err) | ||
251 | return print(err) | ||
252 | end)) then | ||
253 | print("OK") | ||
254 | end | ||
255 | if xpcall(function() | ||
256 | return (func(1)) | ||
257 | end, function(err) | ||
258 | return print(err) | ||
259 | end) then | ||
260 | print("OK") | ||
261 | end | ||
262 | do | ||
263 | do | ||
264 | local success, result = pcall(function() | ||
265 | return func("abc", 123) | ||
266 | end) | ||
267 | if success then | ||
268 | print(result) | ||
269 | end | ||
270 | end | ||
271 | local success, result = xpcall(function() | ||
272 | return func("abc", 123) | ||
273 | end, function(err) | ||
274 | return print(err) | ||
275 | end) | ||
276 | success, result = xpcall(function() | ||
277 | return func("abc", 123) | ||
278 | end, function(err) | ||
279 | return print(err) | ||
280 | end) | ||
281 | if success then | ||
282 | print(result) | ||
283 | end | ||
284 | end | ||
285 | do | ||
286 | pcall(function() | ||
287 | return func(1, 2, 3) | ||
288 | end) | ||
289 | pcall(function() | ||
290 | return func(1, 2, 3) | ||
291 | end) | ||
292 | end | ||
293 | do | ||
294 | x(function() | ||
295 | local tb, a, b, c | ||
296 | local f1 | ||
297 | f1 = function() | ||
298 | return pcall(_anon_func_15, a, b, c, tb) | ||
299 | end | ||
300 | end) | ||
301 | end | ||
302 | do | ||
303 | local f1 | ||
304 | f1 = function() | ||
305 | do | ||
306 | return _anon_func_16(pcall(function() | ||
307 | return func() | ||
308 | end)) | ||
309 | end | ||
310 | end | ||
311 | end | ||
312 | do | ||
313 | local func | ||
314 | local a, b, c | ||
315 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) | ||
316 | if _ok_0 then | ||
317 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
318 | end | ||
319 | end | ||
320 | do | ||
321 | local a, b, c | ||
322 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
323 | return func() | ||
324 | end) | ||
325 | if _ok_0 then | ||
326 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
327 | end | ||
328 | end | ||
329 | do | ||
330 | local a | ||
331 | local _exp_0 = ((function() | ||
332 | return (function(_arg_0, ...) | ||
333 | local _ok_0 = _arg_0 | ||
334 | if _ok_0 then | ||
335 | return ... | ||
336 | end | ||
337 | end)(pcall(function() | ||
338 | return func() | ||
339 | end)) | ||
340 | end)()) | ||
341 | if _exp_0 ~= nil then | ||
342 | a = _exp_0 | ||
343 | else | ||
344 | a = "default" | ||
345 | end | ||
346 | end | ||
347 | do | ||
348 | f((function() | ||
349 | return (function(_arg_0, ...) | ||
350 | local _ok_0 = _arg_0 | ||
351 | if _ok_0 then | ||
352 | return ... | ||
353 | end | ||
354 | end)(pcall(function() | ||
355 | return func() | ||
356 | end)) | ||
357 | end)()) | ||
358 | end | ||
359 | do | ||
360 | f((function() | ||
361 | return (function(_arg_0, ...) | ||
362 | local _ok_0 = _arg_0 | ||
363 | if _ok_0 then | ||
364 | return ... | ||
365 | end | ||
366 | end)(xpcall(function() | ||
367 | print(123) | ||
368 | return func() | ||
369 | end, function(e) | ||
370 | print(e) | ||
371 | return e | ||
372 | end)) | ||
373 | end)()) | ||
374 | end | ||
375 | end | ||
376 | return nil | ||
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index f889865..89c5f8a 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua | |||
@@ -36,17 +36,15 @@ local x | |||
36 | do | 36 | do |
37 | local f = getHandler() | 37 | local f = getHandler() |
38 | if f then | 38 | if f then |
39 | do | 39 | x = ((function() |
40 | f() | 40 | f() |
41 | x = 123 | 41 | return 123 |
42 | end | 42 | end)()) |
43 | end | 43 | end |
44 | end | 44 | end |
45 | local _anon_func_0 = function(print) | 45 | local _anon_func_0 = function(print) |
46 | do | 46 | print(123) |
47 | print(123) | 47 | return { } |
48 | return { } | ||
49 | end | ||
50 | end | 48 | end |
51 | return _(function() | 49 | return _(function() |
52 | setmetatable(a, _anon_func_0(print)) | 50 | setmetatable(a, _anon_func_0(print)) |
diff --git a/spec/outputs/attrib.lua b/spec/outputs/attrib.lua index e48963c..bb9916c 100644 --- a/spec/outputs/attrib.lua +++ b/spec/outputs/attrib.lua | |||
@@ -56,17 +56,21 @@ do | |||
56 | end | 56 | end |
57 | local b | 57 | local b |
58 | if not false then | 58 | if not false then |
59 | if x then | 59 | b = ((function() |
60 | b = 1 | 60 | if x then |
61 | end | 61 | return 1 |
62 | end | ||
63 | end)()) | ||
62 | end | 64 | end |
63 | local _close_0 <close> = b | 65 | local _close_0 <close> = b |
64 | local c | 66 | local c |
65 | if true then | 67 | if true then |
66 | local _exp_0 = x | 68 | c = ((function() |
67 | if "abc" == _exp_0 then | 69 | local _exp_0 = x |
68 | c = 998 | 70 | if "abc" == _exp_0 then |
69 | end | 71 | return 998 |
72 | end | ||
73 | end)()) | ||
70 | end | 74 | end |
71 | local d | 75 | local d |
72 | if (function() | 76 | if (function() |
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index 27f8de5..b7d1236 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua | |||
@@ -20,6 +20,38 @@ local inventory = { | |||
20 | } | 20 | } |
21 | } | 21 | } |
22 | } | 22 | } |
23 | local map | ||
24 | map = function(arr, action) | ||
25 | local _accum_0 = { } | ||
26 | local _len_0 = 1 | ||
27 | for _index_0 = 1, #arr do | ||
28 | local item = arr[_index_0] | ||
29 | _accum_0[_len_0] = action(item) | ||
30 | _len_0 = _len_0 + 1 | ||
31 | end | ||
32 | return _accum_0 | ||
33 | end | ||
34 | local filter | ||
35 | filter = function(arr, cond) | ||
36 | local _accum_0 = { } | ||
37 | local _len_0 = 1 | ||
38 | for _index_0 = 1, #arr do | ||
39 | local item = arr[_index_0] | ||
40 | if cond(item) then | ||
41 | _accum_0[_len_0] = item | ||
42 | _len_0 = _len_0 + 1 | ||
43 | end | ||
44 | end | ||
45 | return _accum_0 | ||
46 | end | ||
47 | local reduce | ||
48 | reduce = function(arr, init, action) | ||
49 | for _index_0 = 1, #arr do | ||
50 | local item = arr[_index_0] | ||
51 | init = action(init, item) | ||
52 | end | ||
53 | return init | ||
54 | end | ||
23 | print(reduce(filter(map({ | 55 | print(reduce(filter(map({ |
24 | 1, | 56 | 1, |
25 | 2, | 57 | 2, |
@@ -77,6 +109,12 @@ end | |||
77 | print("yuescript") | 109 | print("yuescript") |
78 | print(3) | 110 | print(3) |
79 | print("Valid enum type:", "Static") | 111 | print("Valid enum type:", "Static") |
112 | do | ||
113 | print(123, "hello") | ||
114 | end | ||
115 | do | ||
116 | print(123, "hello") | ||
117 | end | ||
80 | if tb ~= nil then | 118 | if tb ~= nil then |
81 | tb:func() | 119 | tb:func() |
82 | end | 120 | end |
@@ -177,6 +215,16 @@ for _key_0, _value_0 in pairs(b) do | |||
177 | end | 215 | end |
178 | end | 216 | end |
179 | merge = _tab_0 | 217 | merge = _tab_0 |
218 | local last | ||
219 | do | ||
220 | local _item_0 = data.items | ||
221 | last = _item_0[#_item_0] | ||
222 | end | ||
223 | local second_last | ||
224 | do | ||
225 | local _item_0 = data.items | ||
226 | second_last = _item_0[#_item_0 - 1] | ||
227 | end | ||
180 | local mt = { } | 228 | local mt = { } |
181 | local add | 229 | local add |
182 | add = function(self, right) | 230 | add = function(self, right) |
@@ -307,6 +355,14 @@ func({ | |||
307 | 2, | 355 | 2, |
308 | 3 | 356 | 3 |
309 | }) | 357 | }) |
358 | local f | ||
359 | f = function() | ||
360 | return { | ||
361 | 1, | ||
362 | 2, | ||
363 | 3 | ||
364 | } | ||
365 | end | ||
310 | local tb = { | 366 | local tb = { |
311 | name = "abc", | 367 | name = "abc", |
312 | values = { | 368 | values = { |
@@ -547,6 +603,59 @@ end | |||
547 | local two, four | 603 | local two, four |
548 | local _obj_0 = items | 604 | local _obj_0 = items |
549 | two, four = _obj_0[2], _obj_0[4] | 605 | two, four = _obj_0[2], _obj_0[4] |
606 | local orders = { | ||
607 | "first", | ||
608 | "second", | ||
609 | "third", | ||
610 | "fourth", | ||
611 | "last" | ||
612 | } | ||
613 | local first, bulk, last = orders[1], (function() | ||
614 | local _accum_0 = { } | ||
615 | local _len_0 = 1 | ||
616 | local _max_0 = #orders + -2 + 1 | ||
617 | for _index_0 = 2, _max_0 do | ||
618 | local _item_0 = orders[_index_0] | ||
619 | _accum_0[_len_0] = _item_0 | ||
620 | _len_0 = _len_0 + 1 | ||
621 | end | ||
622 | return _accum_0 | ||
623 | end)(), orders[#orders] | ||
624 | print(first) | ||
625 | print(bulk) | ||
626 | print(last) | ||
627 | local first, rest | ||
628 | do | ||
629 | local _obj_0 = orders | ||
630 | first, rest = _obj_0[1], (function() | ||
631 | local _accum_0 = { } | ||
632 | local _len_0 = 1 | ||
633 | local _max_0 = #_obj_0 | ||
634 | for _index_0 = 2, _max_0 do | ||
635 | local _item_0 = _obj_0[_index_0] | ||
636 | _accum_0[_len_0] = _item_0 | ||
637 | _len_0 = _len_0 + 1 | ||
638 | end | ||
639 | return _accum_0 | ||
640 | end)() | ||
641 | end | ||
642 | local start, last | ||
643 | do | ||
644 | local _obj_0 = orders | ||
645 | start, last = (function() | ||
646 | local _accum_0 = { } | ||
647 | local _len_0 = 1 | ||
648 | local _max_0 = #_obj_0 + -2 + 1 | ||
649 | for _index_0 = 1, _max_0 do | ||
650 | local _item_0 = _obj_0[_index_0] | ||
651 | _accum_0[_len_0] = _item_0 | ||
652 | _len_0 = _len_0 + 1 | ||
653 | end | ||
654 | return _accum_0 | ||
655 | end)(), _obj_0[#_obj_0] | ||
656 | end | ||
657 | local _obj_0 = orders | ||
658 | first, last = _obj_0[1], _obj_0[#_obj_0] | ||
550 | local tuples = { | 659 | local tuples = { |
551 | { | 660 | { |
552 | "hello", | 661 | "hello", |
@@ -648,6 +757,56 @@ end) | |||
648 | if success then | 757 | if success then |
649 | print(result) | 758 | print(result) |
650 | end | 759 | end |
760 | local a, b, c | ||
761 | do | ||
762 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
763 | return func() | ||
764 | end) | ||
765 | if _ok_0 then | ||
766 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
767 | end | ||
768 | end | ||
769 | do | ||
770 | local _exp_0 = ((function() | ||
771 | return (function(_arg_0, ...) | ||
772 | local _ok_0 = _arg_0 | ||
773 | if _ok_0 then | ||
774 | return ... | ||
775 | end | ||
776 | end)(pcall(function() | ||
777 | return func() | ||
778 | end)) | ||
779 | end)()) | ||
780 | if _exp_0 ~= nil then | ||
781 | a = _exp_0 | ||
782 | else | ||
783 | a = "default" | ||
784 | end | ||
785 | end | ||
786 | f((function() | ||
787 | return (function(_arg_0, ...) | ||
788 | local _ok_0 = _arg_0 | ||
789 | if _ok_0 then | ||
790 | return ... | ||
791 | end | ||
792 | end)(pcall(function() | ||
793 | return func() | ||
794 | end)) | ||
795 | end)()) | ||
796 | f((function() | ||
797 | return (function(_arg_0, ...) | ||
798 | local _ok_0 = _arg_0 | ||
799 | if _ok_0 then | ||
800 | return ... | ||
801 | end | ||
802 | end)(xpcall(function() | ||
803 | print(123) | ||
804 | return func() | ||
805 | end, function(e) | ||
806 | print(e) | ||
807 | return e | ||
808 | end)) | ||
809 | end)()) | ||
651 | local a <const> = 123 | 810 | local a <const> = 123 |
652 | local _ <close> = setmetatable({ }, { | 811 | local _ <close> = setmetatable({ }, { |
653 | __close = function() | 812 | __close = function() |
@@ -657,10 +816,19 @@ local _ <close> = setmetatable({ }, { | |||
657 | local a, b, c, d | 816 | local a, b, c, d |
658 | local _obj_0 = tb | 817 | local _obj_0 = tb |
659 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] | 818 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] |
819 | Constant = 123 | ||
660 | local some_string = "Here is a string\n that has a line break in it." | 820 | local some_string = "Here is a string\n that has a line break in it." |
661 | print("I am " .. tostring(math.random() * 100) .. "% sure.") | 821 | print("I am " .. tostring(math.random() * 100) .. "% sure.") |
662 | local integer = 1000000 | 822 | local integer = 1000000 |
663 | local hex = 0xEFBBBF | 823 | local hex = 0xEFBBBF |
824 | local binary = 19 | ||
825 | local str = "key: value\nlist:\n - item1\n - " .. tostring(expr) | ||
826 | local fn | ||
827 | fn = function() | ||
828 | local str = "foo:\n bar: baz" | ||
829 | return str | ||
830 | end | ||
831 | local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'" | ||
664 | local my_function | 832 | local my_function |
665 | my_function = function() end | 833 | my_function = function() end |
666 | my_function() | 834 | my_function() |
@@ -860,11 +1028,10 @@ for i, item in ipairs(items) do | |||
860 | _len_0 = _len_0 + 1 | 1028 | _len_0 = _len_0 + 1 |
861 | end | 1029 | end |
862 | doubled = _accum_0 | 1030 | doubled = _accum_0 |
863 | local iter = ipairs(items) | ||
864 | local slice | 1031 | local slice |
865 | local _accum_0 = { } | 1032 | local _accum_0 = { } |
866 | local _len_0 = 1 | 1033 | local _len_0 = 1 |
867 | for i, item in iter do | 1034 | for i, item in ipairs(items) do |
868 | if i > 1 and i < 3 then | 1035 | if i > 1 and i < 3 then |
869 | _accum_0[_len_0] = item | 1036 | _accum_0[_len_0] = item |
870 | _len_0 = _len_0 + 1 | 1037 | _len_0 = _len_0 + 1 |
@@ -971,8 +1138,7 @@ local slice | |||
971 | local _accum_0 = { } | 1138 | local _accum_0 = { } |
972 | local _len_0 = 1 | 1139 | local _len_0 = 1 |
973 | local _list_0 = items | 1140 | local _list_0 = items |
974 | local _max_0 = 5 | 1141 | for _index_0 = 1, 5 do |
975 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
976 | local item = _list_0[_index_0] | 1142 | local item = _list_0[_index_0] |
977 | _accum_0[_len_0] = item | 1143 | _accum_0[_len_0] = item |
978 | _len_0 = _len_0 + 1 | 1144 | _len_0 = _len_0 + 1 |
@@ -982,7 +1148,8 @@ local slice | |||
982 | local _accum_0 = { } | 1148 | local _accum_0 = { } |
983 | local _len_0 = 1 | 1149 | local _len_0 = 1 |
984 | local _list_0 = items | 1150 | local _list_0 = items |
985 | for _index_0 = 2, #_list_0 do | 1151 | local _max_0 = #_list_0 |
1152 | for _index_0 = 2, _max_0 do | ||
986 | local item = _list_0[_index_0] | 1153 | local item = _list_0[_index_0] |
987 | _accum_0[_len_0] = item | 1154 | _accum_0[_len_0] = item |
988 | _len_0 = _len_0 + 1 | 1155 | _len_0 = _len_0 + 1 |
@@ -992,12 +1159,46 @@ local slice | |||
992 | local _accum_0 = { } | 1159 | local _accum_0 = { } |
993 | local _len_0 = 1 | 1160 | local _len_0 = 1 |
994 | local _list_0 = items | 1161 | local _list_0 = items |
995 | for _index_0 = 1, #_list_0, 2 do | 1162 | local _max_0 = #_list_0 |
1163 | for _index_0 = 1, _max_0, 2 do | ||
996 | local item = _list_0[_index_0] | 1164 | local item = _list_0[_index_0] |
997 | _accum_0[_len_0] = item | 1165 | _accum_0[_len_0] = item |
998 | _len_0 = _len_0 + 1 | 1166 | _len_0 = _len_0 + 1 |
999 | end | 1167 | end |
1000 | slice = _accum_0 | 1168 | slice = _accum_0 |
1169 | local slice | ||
1170 | local _accum_0 = { } | ||
1171 | local _len_0 = 1 | ||
1172 | local _list_0 = items | ||
1173 | local _min_0 = #_list_0 + -4 + 1 | ||
1174 | local _max_0 = #_list_0 + -1 + 1 | ||
1175 | for _index_0 = _min_0, _max_0 do | ||
1176 | local item = _list_0[_index_0] | ||
1177 | _accum_0[_len_0] = item | ||
1178 | _len_0 = _len_0 + 1 | ||
1179 | end | ||
1180 | slice = _accum_0 | ||
1181 | local reverse_slice | ||
1182 | local _accum_0 = { } | ||
1183 | local _len_0 = 1 | ||
1184 | local _list_0 = items | ||
1185 | local _min_0 = #_list_0 + -1 + 1 | ||
1186 | for _index_0 = _min_0, 1, -1 do | ||
1187 | local item = _list_0[_index_0] | ||
1188 | _accum_0[_len_0] = item | ||
1189 | _len_0 = _len_0 + 1 | ||
1190 | end | ||
1191 | reverse_slice = _accum_0 | ||
1192 | local sub_list | ||
1193 | local _accum_0 = { } | ||
1194 | local _len_0 = 1 | ||
1195 | local _list_0 = items | ||
1196 | for _index_0 = 2, 4 do | ||
1197 | local _item_0 = _list_0[_index_0] | ||
1198 | _accum_0[_len_0] = _item_0 | ||
1199 | _len_0 = _len_0 + 1 | ||
1200 | end | ||
1201 | sub_list = _accum_0 | ||
1001 | for i = 10, 20 do | 1202 | for i = 10, 20 do |
1002 | print(i) | 1203 | print(i) |
1003 | end | 1204 | end |
@@ -1008,8 +1209,7 @@ for key, value in pairs(object) do | |||
1008 | print(key, value) | 1209 | print(key, value) |
1009 | end | 1210 | end |
1010 | local _list_0 = items | 1211 | local _list_0 = items |
1011 | local _max_0 = 4 | 1212 | for _index_0 = 2, 4 do |
1012 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
1013 | local item = _list_0[_index_0] | 1213 | local item = _list_0[_index_0] |
1014 | print(item) | 1214 | print(item) |
1015 | end | 1215 | end |
@@ -1027,12 +1227,24 @@ local _len_0 = 1 | |||
1027 | for i = 1, 20 do | 1227 | for i = 1, 20 do |
1028 | if i % 2 == 0 then | 1228 | if i % 2 == 0 then |
1029 | _accum_0[_len_0] = i * 2 | 1229 | _accum_0[_len_0] = i * 2 |
1230 | _len_0 = _len_0 + 1 | ||
1030 | else | 1231 | else |
1031 | _accum_0[_len_0] = i | 1232 | _accum_0[_len_0] = i |
1233 | _len_0 = _len_0 + 1 | ||
1032 | end | 1234 | end |
1033 | _len_0 = _len_0 + 1 | ||
1034 | end | 1235 | end |
1035 | doubled_evens = _accum_0 | 1236 | doubled_evens = _accum_0 |
1237 | local first_large | ||
1238 | local _accum_0 | ||
1239 | local _list_0 = numbers | ||
1240 | for _index_0 = 1, #_list_0 do | ||
1241 | local n = _list_0[_index_0] | ||
1242 | if n > 10 then | ||
1243 | _accum_0 = n | ||
1244 | break | ||
1245 | end | ||
1246 | end | ||
1247 | first_large = _accum_0 | ||
1036 | local func_a | 1248 | local func_a |
1037 | func_a = function() | 1249 | func_a = function() |
1038 | for i = 1, 10 do | 1250 | for i = 1, 10 do |
@@ -1181,7 +1393,7 @@ if "Robert" == name then | |||
1181 | elseif "Dan" == name or "Daniel" == name then | 1393 | elseif "Dan" == name or "Daniel" == name then |
1182 | print("Your name, it's Dan") | 1394 | print("Your name, it's Dan") |
1183 | else | 1395 | else |
1184 | print("I don't know about your name") | 1396 | print("I don't know about you with name " .. tostring(name)) |
1185 | end | 1397 | end |
1186 | local b = 1 | 1398 | local b = 1 |
1187 | local next_number | 1399 | local next_number |
@@ -1281,6 +1493,192 @@ if _tab_0 then | |||
1281 | end | 1493 | end |
1282 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) | 1494 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) |
1283 | end | 1495 | end |
1496 | local _exp_0 = tb | ||
1497 | local _type_0 = type(_exp_0) | ||
1498 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1499 | local _match_0 = false | ||
1500 | if _tab_0 then | ||
1501 | if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then | ||
1502 | _match_0 = true | ||
1503 | print("1, 2, 3") | ||
1504 | end | ||
1505 | end | ||
1506 | if not _match_0 then | ||
1507 | local _match_1 = false | ||
1508 | if _tab_0 then | ||
1509 | local b = _exp_0[2] | ||
1510 | if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then | ||
1511 | _match_1 = true | ||
1512 | print("1, " .. tostring(b) .. ", 3") | ||
1513 | end | ||
1514 | end | ||
1515 | if not _match_1 then | ||
1516 | if _tab_0 then | ||
1517 | local b = _exp_0[3] | ||
1518 | if b == nil then | ||
1519 | b = 3 | ||
1520 | end | ||
1521 | if 1 == _exp_0[1] and 2 == _exp_0[2] then | ||
1522 | print("1, 2, " .. tostring(b)) | ||
1523 | end | ||
1524 | end | ||
1525 | end | ||
1526 | end | ||
1527 | local _exp_0 = tb | ||
1528 | local _type_0 = type(_exp_0) | ||
1529 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1530 | local _match_0 = false | ||
1531 | if _tab_0 then | ||
1532 | local result = _exp_0.result | ||
1533 | if true == _exp_0.success and result ~= nil then | ||
1534 | _match_0 = true | ||
1535 | print("success", result) | ||
1536 | end | ||
1537 | end | ||
1538 | if not _match_0 then | ||
1539 | local _match_1 = false | ||
1540 | if _tab_0 then | ||
1541 | if false == _exp_0.success then | ||
1542 | _match_1 = true | ||
1543 | print("failed", result) | ||
1544 | end | ||
1545 | end | ||
1546 | if not _match_1 then | ||
1547 | print("invalid") | ||
1548 | end | ||
1549 | end | ||
1550 | local _exp_0 = tb | ||
1551 | local _type_0 = type(_exp_0) | ||
1552 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1553 | local _match_0 = false | ||
1554 | if _tab_0 then | ||
1555 | local content | ||
1556 | do | ||
1557 | local _obj_0 = _exp_0.data | ||
1558 | local _type_1 = type(_obj_0) | ||
1559 | if "table" == _type_1 or "userdata" == _type_1 then | ||
1560 | content = _obj_0.content | ||
1561 | end | ||
1562 | end | ||
1563 | local _val_0 | ||
1564 | do | ||
1565 | local _obj_0 = _exp_0.data | ||
1566 | if _obj_0 ~= nil then | ||
1567 | _val_0 = _obj_0.type | ||
1568 | end | ||
1569 | end | ||
1570 | if "success" == _val_0 and content ~= nil then | ||
1571 | _match_0 = true | ||
1572 | print("success", content) | ||
1573 | end | ||
1574 | end | ||
1575 | if not _match_0 then | ||
1576 | local _match_1 = false | ||
1577 | if _tab_0 then | ||
1578 | local content | ||
1579 | do | ||
1580 | local _obj_0 = _exp_0.data | ||
1581 | local _type_1 = type(_obj_0) | ||
1582 | if "table" == _type_1 or "userdata" == _type_1 then | ||
1583 | content = _obj_0.content | ||
1584 | end | ||
1585 | end | ||
1586 | local _val_0 | ||
1587 | do | ||
1588 | local _obj_0 = _exp_0.data | ||
1589 | if _obj_0 ~= nil then | ||
1590 | _val_0 = _obj_0.type | ||
1591 | end | ||
1592 | end | ||
1593 | if "error" == _val_0 and content ~= nil then | ||
1594 | _match_1 = true | ||
1595 | print("failed", content) | ||
1596 | end | ||
1597 | end | ||
1598 | if not _match_1 then | ||
1599 | print("invalid") | ||
1600 | end | ||
1601 | end | ||
1602 | local _exp_0 = tb | ||
1603 | local _type_0 = type(_exp_0) | ||
1604 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1605 | if _tab_0 then | ||
1606 | local fourth = _exp_0[4] | ||
1607 | local _val_0 | ||
1608 | do | ||
1609 | local _obj_0 = _exp_0[1] | ||
1610 | if _obj_0 ~= nil then | ||
1611 | _val_0 = _obj_0.a | ||
1612 | end | ||
1613 | end | ||
1614 | local _val_1 | ||
1615 | do | ||
1616 | local _obj_0 = _exp_0[1] | ||
1617 | if _obj_0 ~= nil then | ||
1618 | _val_1 = _obj_0.b | ||
1619 | end | ||
1620 | end | ||
1621 | local _val_2 | ||
1622 | do | ||
1623 | local _obj_0 = _exp_0[2] | ||
1624 | if _obj_0 ~= nil then | ||
1625 | _val_2 = _obj_0.a | ||
1626 | end | ||
1627 | end | ||
1628 | local _val_3 | ||
1629 | do | ||
1630 | local _obj_0 = _exp_0[2] | ||
1631 | if _obj_0 ~= nil then | ||
1632 | _val_3 = _obj_0.b | ||
1633 | end | ||
1634 | end | ||
1635 | local _val_4 | ||
1636 | do | ||
1637 | local _obj_0 = _exp_0[3] | ||
1638 | if _obj_0 ~= nil then | ||
1639 | _val_4 = _obj_0.a | ||
1640 | end | ||
1641 | end | ||
1642 | local _val_5 | ||
1643 | do | ||
1644 | local _obj_0 = _exp_0[3] | ||
1645 | if _obj_0 ~= nil then | ||
1646 | _val_5 = _obj_0.b | ||
1647 | end | ||
1648 | end | ||
1649 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then | ||
1650 | print("matched", fourth) | ||
1651 | end | ||
1652 | end | ||
1653 | local segments = { | ||
1654 | "admin", | ||
1655 | "users", | ||
1656 | "logs", | ||
1657 | "view" | ||
1658 | } | ||
1659 | local _type_0 = type(segments) | ||
1660 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1661 | if _tab_0 then | ||
1662 | local groups | ||
1663 | do | ||
1664 | local _accum_0 = { } | ||
1665 | local _len_0 = 1 | ||
1666 | local _max_0 = #segments + -3 + 1 | ||
1667 | for _index_0 = 1, _max_0 do | ||
1668 | local _item_0 = segments[_index_0] | ||
1669 | _accum_0[_len_0] = _item_0 | ||
1670 | _len_0 = _len_0 + 1 | ||
1671 | end | ||
1672 | groups = _accum_0 | ||
1673 | end | ||
1674 | local resource = segments[#segments - 1] | ||
1675 | local action = segments[#segments] | ||
1676 | if resource ~= nil and action ~= nil then | ||
1677 | print("Group:", groups) | ||
1678 | print("Resource:", resource) | ||
1679 | print("Action:", action) | ||
1680 | end | ||
1681 | end | ||
1284 | local Inventory | 1682 | local Inventory |
1285 | local _class_0 | 1683 | local _class_0 |
1286 | local _base_0 = { | 1684 | local _base_0 = { |
@@ -1937,6 +2335,10 @@ do | |||
1937 | _with_1["key-name"] = value | 2335 | _with_1["key-name"] = value |
1938 | end | 2336 | end |
1939 | _with_0[#_with_0 + 1] = "abc" | 2337 | _with_0[#_with_0 + 1] = "abc" |
2338 | local _with_0 = obj | ||
2339 | if _with_0 ~= nil then | ||
2340 | print(obj.name) | ||
2341 | end | ||
1940 | do | 2342 | do |
1941 | local var = "hello" | 2343 | local var = "hello" |
1942 | print(var) | 2344 | print(var) |
@@ -2027,6 +2429,38 @@ local inventory = { | |||
2027 | } | 2429 | } |
2028 | } | 2430 | } |
2029 | } | 2431 | } |
2432 | local map | ||
2433 | map = function(arr, action) | ||
2434 | local _accum_0 = { } | ||
2435 | local _len_0 = 1 | ||
2436 | for _index_0 = 1, #arr do | ||
2437 | local item = arr[_index_0] | ||
2438 | _accum_0[_len_0] = action(item) | ||
2439 | _len_0 = _len_0 + 1 | ||
2440 | end | ||
2441 | return _accum_0 | ||
2442 | end | ||
2443 | local filter | ||
2444 | filter = function(arr, cond) | ||
2445 | local _accum_0 = { } | ||
2446 | local _len_0 = 1 | ||
2447 | for _index_0 = 1, #arr do | ||
2448 | local item = arr[_index_0] | ||
2449 | if cond(item) then | ||
2450 | _accum_0[_len_0] = item | ||
2451 | _len_0 = _len_0 + 1 | ||
2452 | end | ||
2453 | end | ||
2454 | return _accum_0 | ||
2455 | end | ||
2456 | local reduce | ||
2457 | reduce = function(arr, init, action) | ||
2458 | for _index_0 = 1, #arr do | ||
2459 | local item = arr[_index_0] | ||
2460 | init = action(init, item) | ||
2461 | end | ||
2462 | return init | ||
2463 | end | ||
2030 | print(reduce(filter(map({ | 2464 | print(reduce(filter(map({ |
2031 | 1, | 2465 | 1, |
2032 | 2, | 2466 | 2, |
@@ -2084,6 +2518,12 @@ end | |||
2084 | print("yuescript") | 2518 | print("yuescript") |
2085 | print(3) | 2519 | print(3) |
2086 | print("Valid enum type:", "Static") | 2520 | print("Valid enum type:", "Static") |
2521 | do | ||
2522 | print(123, "hello") | ||
2523 | end | ||
2524 | do | ||
2525 | print(123, "hello") | ||
2526 | end | ||
2087 | if tb ~= nil then | 2527 | if tb ~= nil then |
2088 | tb:func() | 2528 | tb:func() |
2089 | end | 2529 | end |
@@ -2184,6 +2624,16 @@ for _key_0, _value_0 in pairs(b) do | |||
2184 | end | 2624 | end |
2185 | end | 2625 | end |
2186 | merge = _tab_0 | 2626 | merge = _tab_0 |
2627 | local last | ||
2628 | do | ||
2629 | local _item_0 = data.items | ||
2630 | last = _item_0[#_item_0] | ||
2631 | end | ||
2632 | local second_last | ||
2633 | do | ||
2634 | local _item_0 = data.items | ||
2635 | second_last = _item_0[#_item_0 - 1] | ||
2636 | end | ||
2187 | local mt = { } | 2637 | local mt = { } |
2188 | local add | 2638 | local add |
2189 | add = function(self, right) | 2639 | add = function(self, right) |
@@ -2314,6 +2764,14 @@ func({ | |||
2314 | 2, | 2764 | 2, |
2315 | 3 | 2765 | 3 |
2316 | }) | 2766 | }) |
2767 | local f | ||
2768 | f = function() | ||
2769 | return { | ||
2770 | 1, | ||
2771 | 2, | ||
2772 | 3 | ||
2773 | } | ||
2774 | end | ||
2317 | local tb = { | 2775 | local tb = { |
2318 | name = "abc", | 2776 | name = "abc", |
2319 | values = { | 2777 | values = { |
@@ -2554,6 +3012,59 @@ end | |||
2554 | local two, four | 3012 | local two, four |
2555 | local _obj_0 = items | 3013 | local _obj_0 = items |
2556 | two, four = _obj_0[2], _obj_0[4] | 3014 | two, four = _obj_0[2], _obj_0[4] |
3015 | local orders = { | ||
3016 | "first", | ||
3017 | "second", | ||
3018 | "third", | ||
3019 | "fourth", | ||
3020 | "last" | ||
3021 | } | ||
3022 | local first, bulk, last = orders[1], (function() | ||
3023 | local _accum_0 = { } | ||
3024 | local _len_0 = 1 | ||
3025 | local _max_0 = #orders + -2 + 1 | ||
3026 | for _index_0 = 2, _max_0 do | ||
3027 | local _item_0 = orders[_index_0] | ||
3028 | _accum_0[_len_0] = _item_0 | ||
3029 | _len_0 = _len_0 + 1 | ||
3030 | end | ||
3031 | return _accum_0 | ||
3032 | end)(), orders[#orders] | ||
3033 | print(first) | ||
3034 | print(bulk) | ||
3035 | print(last) | ||
3036 | local first, rest | ||
3037 | do | ||
3038 | local _obj_0 = orders | ||
3039 | first, rest = _obj_0[1], (function() | ||
3040 | local _accum_0 = { } | ||
3041 | local _len_0 = 1 | ||
3042 | local _max_0 = #_obj_0 | ||
3043 | for _index_0 = 2, _max_0 do | ||
3044 | local _item_0 = _obj_0[_index_0] | ||
3045 | _accum_0[_len_0] = _item_0 | ||
3046 | _len_0 = _len_0 + 1 | ||
3047 | end | ||
3048 | return _accum_0 | ||
3049 | end)() | ||
3050 | end | ||
3051 | local start, last | ||
3052 | do | ||
3053 | local _obj_0 = orders | ||
3054 | start, last = (function() | ||
3055 | local _accum_0 = { } | ||
3056 | local _len_0 = 1 | ||
3057 | local _max_0 = #_obj_0 + -2 + 1 | ||
3058 | for _index_0 = 1, _max_0 do | ||
3059 | local _item_0 = _obj_0[_index_0] | ||
3060 | _accum_0[_len_0] = _item_0 | ||
3061 | _len_0 = _len_0 + 1 | ||
3062 | end | ||
3063 | return _accum_0 | ||
3064 | end)(), _obj_0[#_obj_0] | ||
3065 | end | ||
3066 | local _obj_0 = orders | ||
3067 | first, last = _obj_0[1], _obj_0[#_obj_0] | ||
2557 | local tuples = { | 3068 | local tuples = { |
2558 | { | 3069 | { |
2559 | "hello", | 3070 | "hello", |
@@ -2655,6 +3166,56 @@ end) | |||
2655 | if success then | 3166 | if success then |
2656 | print(result) | 3167 | print(result) |
2657 | end | 3168 | end |
3169 | local a, b, c | ||
3170 | do | ||
3171 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
3172 | return func() | ||
3173 | end) | ||
3174 | if _ok_0 then | ||
3175 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
3176 | end | ||
3177 | end | ||
3178 | do | ||
3179 | local _exp_0 = ((function() | ||
3180 | return (function(_arg_0, ...) | ||
3181 | local _ok_0 = _arg_0 | ||
3182 | if _ok_0 then | ||
3183 | return ... | ||
3184 | end | ||
3185 | end)(pcall(function() | ||
3186 | return func() | ||
3187 | end)) | ||
3188 | end)()) | ||
3189 | if _exp_0 ~= nil then | ||
3190 | a = _exp_0 | ||
3191 | else | ||
3192 | a = "default" | ||
3193 | end | ||
3194 | end | ||
3195 | f((function() | ||
3196 | return (function(_arg_0, ...) | ||
3197 | local _ok_0 = _arg_0 | ||
3198 | if _ok_0 then | ||
3199 | return ... | ||
3200 | end | ||
3201 | end)(pcall(function() | ||
3202 | return func() | ||
3203 | end)) | ||
3204 | end)()) | ||
3205 | f((function() | ||
3206 | return (function(_arg_0, ...) | ||
3207 | local _ok_0 = _arg_0 | ||
3208 | if _ok_0 then | ||
3209 | return ... | ||
3210 | end | ||
3211 | end)(xpcall(function() | ||
3212 | print(123) | ||
3213 | return func() | ||
3214 | end, function(e) | ||
3215 | print(e) | ||
3216 | return e | ||
3217 | end)) | ||
3218 | end)()) | ||
2658 | local a <const> = 123 | 3219 | local a <const> = 123 |
2659 | local _ <close> = setmetatable({ }, { | 3220 | local _ <close> = setmetatable({ }, { |
2660 | __close = function() | 3221 | __close = function() |
@@ -2664,10 +3225,19 @@ local _ <close> = setmetatable({ }, { | |||
2664 | local a, b, c, d | 3225 | local a, b, c, d |
2665 | local _obj_0 = tb | 3226 | local _obj_0 = tb |
2666 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] | 3227 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] |
3228 | Constant = 123 | ||
2667 | local some_string = "Here is a string\n that has a line break in it." | 3229 | local some_string = "Here is a string\n that has a line break in it." |
2668 | print("I am " .. tostring(math.random() * 100) .. "% sure.") | 3230 | print("I am " .. tostring(math.random() * 100) .. "% sure.") |
2669 | local integer = 1000000 | 3231 | local integer = 1000000 |
2670 | local hex = 0xEFBBBF | 3232 | local hex = 0xEFBBBF |
3233 | local binary = 19 | ||
3234 | local str = "key: value\nlist:\n - item1\n - " .. tostring(expr) | ||
3235 | local fn | ||
3236 | fn = function() | ||
3237 | local str = "foo:\n bar: baz" | ||
3238 | return str | ||
3239 | end | ||
3240 | local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'" | ||
2671 | local my_function | 3241 | local my_function |
2672 | my_function = function() end | 3242 | my_function = function() end |
2673 | my_function() | 3243 | my_function() |
@@ -2867,11 +3437,10 @@ for i, item in ipairs(items) do | |||
2867 | _len_0 = _len_0 + 1 | 3437 | _len_0 = _len_0 + 1 |
2868 | end | 3438 | end |
2869 | doubled = _accum_0 | 3439 | doubled = _accum_0 |
2870 | local iter = ipairs(items) | ||
2871 | local slice | 3440 | local slice |
2872 | local _accum_0 = { } | 3441 | local _accum_0 = { } |
2873 | local _len_0 = 1 | 3442 | local _len_0 = 1 |
2874 | for i, item in iter do | 3443 | for i, item in ipairs(items) do |
2875 | if i > 1 and i < 3 then | 3444 | if i > 1 and i < 3 then |
2876 | _accum_0[_len_0] = item | 3445 | _accum_0[_len_0] = item |
2877 | _len_0 = _len_0 + 1 | 3446 | _len_0 = _len_0 + 1 |
@@ -2978,8 +3547,7 @@ local slice | |||
2978 | local _accum_0 = { } | 3547 | local _accum_0 = { } |
2979 | local _len_0 = 1 | 3548 | local _len_0 = 1 |
2980 | local _list_0 = items | 3549 | local _list_0 = items |
2981 | local _max_0 = 5 | 3550 | for _index_0 = 1, 5 do |
2982 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
2983 | local item = _list_0[_index_0] | 3551 | local item = _list_0[_index_0] |
2984 | _accum_0[_len_0] = item | 3552 | _accum_0[_len_0] = item |
2985 | _len_0 = _len_0 + 1 | 3553 | _len_0 = _len_0 + 1 |
@@ -2989,7 +3557,8 @@ local slice | |||
2989 | local _accum_0 = { } | 3557 | local _accum_0 = { } |
2990 | local _len_0 = 1 | 3558 | local _len_0 = 1 |
2991 | local _list_0 = items | 3559 | local _list_0 = items |
2992 | for _index_0 = 2, #_list_0 do | 3560 | local _max_0 = #_list_0 |
3561 | for _index_0 = 2, _max_0 do | ||
2993 | local item = _list_0[_index_0] | 3562 | local item = _list_0[_index_0] |
2994 | _accum_0[_len_0] = item | 3563 | _accum_0[_len_0] = item |
2995 | _len_0 = _len_0 + 1 | 3564 | _len_0 = _len_0 + 1 |
@@ -2999,12 +3568,46 @@ local slice | |||
2999 | local _accum_0 = { } | 3568 | local _accum_0 = { } |
3000 | local _len_0 = 1 | 3569 | local _len_0 = 1 |
3001 | local _list_0 = items | 3570 | local _list_0 = items |
3002 | for _index_0 = 1, #_list_0, 2 do | 3571 | local _max_0 = #_list_0 |
3572 | for _index_0 = 1, _max_0, 2 do | ||
3003 | local item = _list_0[_index_0] | 3573 | local item = _list_0[_index_0] |
3004 | _accum_0[_len_0] = item | 3574 | _accum_0[_len_0] = item |
3005 | _len_0 = _len_0 + 1 | 3575 | _len_0 = _len_0 + 1 |
3006 | end | 3576 | end |
3007 | slice = _accum_0 | 3577 | slice = _accum_0 |
3578 | local slice | ||
3579 | local _accum_0 = { } | ||
3580 | local _len_0 = 1 | ||
3581 | local _list_0 = items | ||
3582 | local _min_0 = #_list_0 + -4 + 1 | ||
3583 | local _max_0 = #_list_0 + -1 + 1 | ||
3584 | for _index_0 = _min_0, _max_0 do | ||
3585 | local item = _list_0[_index_0] | ||
3586 | _accum_0[_len_0] = item | ||
3587 | _len_0 = _len_0 + 1 | ||
3588 | end | ||
3589 | slice = _accum_0 | ||
3590 | local reverse_slice | ||
3591 | local _accum_0 = { } | ||
3592 | local _len_0 = 1 | ||
3593 | local _list_0 = items | ||
3594 | local _min_0 = #_list_0 + -1 + 1 | ||
3595 | for _index_0 = _min_0, 1, -1 do | ||
3596 | local item = _list_0[_index_0] | ||
3597 | _accum_0[_len_0] = item | ||
3598 | _len_0 = _len_0 + 1 | ||
3599 | end | ||
3600 | reverse_slice = _accum_0 | ||
3601 | local sub_list | ||
3602 | local _accum_0 = { } | ||
3603 | local _len_0 = 1 | ||
3604 | local _list_0 = items | ||
3605 | for _index_0 = 2, 4 do | ||
3606 | local _item_0 = _list_0[_index_0] | ||
3607 | _accum_0[_len_0] = _item_0 | ||
3608 | _len_0 = _len_0 + 1 | ||
3609 | end | ||
3610 | sub_list = _accum_0 | ||
3008 | for i = 10, 20 do | 3611 | for i = 10, 20 do |
3009 | print(i) | 3612 | print(i) |
3010 | end | 3613 | end |
@@ -3015,8 +3618,7 @@ for key, value in pairs(object) do | |||
3015 | print(key, value) | 3618 | print(key, value) |
3016 | end | 3619 | end |
3017 | local _list_0 = items | 3620 | local _list_0 = items |
3018 | local _max_0 = 4 | 3621 | for _index_0 = 2, 4 do |
3019 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
3020 | local item = _list_0[_index_0] | 3622 | local item = _list_0[_index_0] |
3021 | print(item) | 3623 | print(item) |
3022 | end | 3624 | end |
@@ -3034,12 +3636,24 @@ local _len_0 = 1 | |||
3034 | for i = 1, 20 do | 3636 | for i = 1, 20 do |
3035 | if i % 2 == 0 then | 3637 | if i % 2 == 0 then |
3036 | _accum_0[_len_0] = i * 2 | 3638 | _accum_0[_len_0] = i * 2 |
3639 | _len_0 = _len_0 + 1 | ||
3037 | else | 3640 | else |
3038 | _accum_0[_len_0] = i | 3641 | _accum_0[_len_0] = i |
3642 | _len_0 = _len_0 + 1 | ||
3039 | end | 3643 | end |
3040 | _len_0 = _len_0 + 1 | ||
3041 | end | 3644 | end |
3042 | doubled_evens = _accum_0 | 3645 | doubled_evens = _accum_0 |
3646 | local first_large | ||
3647 | local _accum_0 | ||
3648 | local _list_0 = numbers | ||
3649 | for _index_0 = 1, #_list_0 do | ||
3650 | local n = _list_0[_index_0] | ||
3651 | if n > 10 then | ||
3652 | _accum_0 = n | ||
3653 | break | ||
3654 | end | ||
3655 | end | ||
3656 | first_large = _accum_0 | ||
3043 | local func_a | 3657 | local func_a |
3044 | func_a = function() | 3658 | func_a = function() |
3045 | for i = 1, 10 do | 3659 | for i = 1, 10 do |
@@ -3188,7 +3802,7 @@ if "Robert" == name then | |||
3188 | elseif "Dan" == name or "Daniel" == name then | 3802 | elseif "Dan" == name or "Daniel" == name then |
3189 | print("Your name, it's Dan") | 3803 | print("Your name, it's Dan") |
3190 | else | 3804 | else |
3191 | print("I don't know about your name") | 3805 | print("I don't know about you with name " .. tostring(name)) |
3192 | end | 3806 | end |
3193 | local b = 1 | 3807 | local b = 1 |
3194 | local next_number | 3808 | local next_number |
@@ -3288,6 +3902,192 @@ if _tab_0 then | |||
3288 | end | 3902 | end |
3289 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) | 3903 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) |
3290 | end | 3904 | end |
3905 | local _exp_0 = tb | ||
3906 | local _type_0 = type(_exp_0) | ||
3907 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3908 | local _match_0 = false | ||
3909 | if _tab_0 then | ||
3910 | if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then | ||
3911 | _match_0 = true | ||
3912 | print("1, 2, 3") | ||
3913 | end | ||
3914 | end | ||
3915 | if not _match_0 then | ||
3916 | local _match_1 = false | ||
3917 | if _tab_0 then | ||
3918 | local b = _exp_0[2] | ||
3919 | if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then | ||
3920 | _match_1 = true | ||
3921 | print("1, " .. tostring(b) .. ", 3") | ||
3922 | end | ||
3923 | end | ||
3924 | if not _match_1 then | ||
3925 | if _tab_0 then | ||
3926 | local b = _exp_0[3] | ||
3927 | if b == nil then | ||
3928 | b = 3 | ||
3929 | end | ||
3930 | if 1 == _exp_0[1] and 2 == _exp_0[2] then | ||
3931 | print("1, 2, " .. tostring(b)) | ||
3932 | end | ||
3933 | end | ||
3934 | end | ||
3935 | end | ||
3936 | local _exp_0 = tb | ||
3937 | local _type_0 = type(_exp_0) | ||
3938 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3939 | local _match_0 = false | ||
3940 | if _tab_0 then | ||
3941 | local result = _exp_0.result | ||
3942 | if true == _exp_0.success and result ~= nil then | ||
3943 | _match_0 = true | ||
3944 | print("success", result) | ||
3945 | end | ||
3946 | end | ||
3947 | if not _match_0 then | ||
3948 | local _match_1 = false | ||
3949 | if _tab_0 then | ||
3950 | if false == _exp_0.success then | ||
3951 | _match_1 = true | ||
3952 | print("failed", result) | ||
3953 | end | ||
3954 | end | ||
3955 | if not _match_1 then | ||
3956 | print("invalid") | ||
3957 | end | ||
3958 | end | ||
3959 | local _exp_0 = tb | ||
3960 | local _type_0 = type(_exp_0) | ||
3961 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3962 | local _match_0 = false | ||
3963 | if _tab_0 then | ||
3964 | local content | ||
3965 | do | ||
3966 | local _obj_0 = _exp_0.data | ||
3967 | local _type_1 = type(_obj_0) | ||
3968 | if "table" == _type_1 or "userdata" == _type_1 then | ||
3969 | content = _obj_0.content | ||
3970 | end | ||
3971 | end | ||
3972 | local _val_0 | ||
3973 | do | ||
3974 | local _obj_0 = _exp_0.data | ||
3975 | if _obj_0 ~= nil then | ||
3976 | _val_0 = _obj_0.type | ||
3977 | end | ||
3978 | end | ||
3979 | if "success" == _val_0 and content ~= nil then | ||
3980 | _match_0 = true | ||
3981 | print("success", content) | ||
3982 | end | ||
3983 | end | ||
3984 | if not _match_0 then | ||
3985 | local _match_1 = false | ||
3986 | if _tab_0 then | ||
3987 | local content | ||
3988 | do | ||
3989 | local _obj_0 = _exp_0.data | ||
3990 | local _type_1 = type(_obj_0) | ||
3991 | if "table" == _type_1 or "userdata" == _type_1 then | ||
3992 | content = _obj_0.content | ||
3993 | end | ||
3994 | end | ||
3995 | local _val_0 | ||
3996 | do | ||
3997 | local _obj_0 = _exp_0.data | ||
3998 | if _obj_0 ~= nil then | ||
3999 | _val_0 = _obj_0.type | ||
4000 | end | ||
4001 | end | ||
4002 | if "error" == _val_0 and content ~= nil then | ||
4003 | _match_1 = true | ||
4004 | print("failed", content) | ||
4005 | end | ||
4006 | end | ||
4007 | if not _match_1 then | ||
4008 | print("invalid") | ||
4009 | end | ||
4010 | end | ||
4011 | local _exp_0 = tb | ||
4012 | local _type_0 = type(_exp_0) | ||
4013 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
4014 | if _tab_0 then | ||
4015 | local fourth = _exp_0[4] | ||
4016 | local _val_0 | ||
4017 | do | ||
4018 | local _obj_0 = _exp_0[1] | ||
4019 | if _obj_0 ~= nil then | ||
4020 | _val_0 = _obj_0.a | ||
4021 | end | ||
4022 | end | ||
4023 | local _val_1 | ||
4024 | do | ||
4025 | local _obj_0 = _exp_0[1] | ||
4026 | if _obj_0 ~= nil then | ||
4027 | _val_1 = _obj_0.b | ||
4028 | end | ||
4029 | end | ||
4030 | local _val_2 | ||
4031 | do | ||
4032 | local _obj_0 = _exp_0[2] | ||
4033 | if _obj_0 ~= nil then | ||
4034 | _val_2 = _obj_0.a | ||
4035 | end | ||
4036 | end | ||
4037 | local _val_3 | ||
4038 | do | ||
4039 | local _obj_0 = _exp_0[2] | ||
4040 | if _obj_0 ~= nil then | ||
4041 | _val_3 = _obj_0.b | ||
4042 | end | ||
4043 | end | ||
4044 | local _val_4 | ||
4045 | do | ||
4046 | local _obj_0 = _exp_0[3] | ||
4047 | if _obj_0 ~= nil then | ||
4048 | _val_4 = _obj_0.a | ||
4049 | end | ||
4050 | end | ||
4051 | local _val_5 | ||
4052 | do | ||
4053 | local _obj_0 = _exp_0[3] | ||
4054 | if _obj_0 ~= nil then | ||
4055 | _val_5 = _obj_0.b | ||
4056 | end | ||
4057 | end | ||
4058 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then | ||
4059 | print("matched", fourth) | ||
4060 | end | ||
4061 | end | ||
4062 | local segments = { | ||
4063 | "admin", | ||
4064 | "users", | ||
4065 | "logs", | ||
4066 | "view" | ||
4067 | } | ||
4068 | local _type_0 = type(segments) | ||
4069 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
4070 | if _tab_0 then | ||
4071 | local groups | ||
4072 | do | ||
4073 | local _accum_0 = { } | ||
4074 | local _len_0 = 1 | ||
4075 | local _max_0 = #segments + -3 + 1 | ||
4076 | for _index_0 = 1, _max_0 do | ||
4077 | local _item_0 = segments[_index_0] | ||
4078 | _accum_0[_len_0] = _item_0 | ||
4079 | _len_0 = _len_0 + 1 | ||
4080 | end | ||
4081 | groups = _accum_0 | ||
4082 | end | ||
4083 | local resource = segments[#segments - 1] | ||
4084 | local action = segments[#segments] | ||
4085 | if resource ~= nil and action ~= nil then | ||
4086 | print("Group:", groups) | ||
4087 | print("Resource:", resource) | ||
4088 | print("Action:", action) | ||
4089 | end | ||
4090 | end | ||
3291 | local Inventory | 4091 | local Inventory |
3292 | local _class_0 | 4092 | local _class_0 |
3293 | local _base_0 = { | 4093 | local _base_0 = { |
@@ -3944,6 +4744,10 @@ do | |||
3944 | _with_1["key-name"] = value | 4744 | _with_1["key-name"] = value |
3945 | end | 4745 | end |
3946 | _with_0[#_with_0 + 1] = "abc" | 4746 | _with_0[#_with_0 + 1] = "abc" |
4747 | local _with_0 = obj | ||
4748 | if _with_0 ~= nil then | ||
4749 | print(obj.name) | ||
4750 | end | ||
3947 | do | 4751 | do |
3948 | local var = "hello" | 4752 | local var = "hello" |
3949 | print(var) | 4753 | print(var) |
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index ffa0483..b54d6d7 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua | |||
@@ -20,6 +20,38 @@ local inventory = { | |||
20 | } | 20 | } |
21 | } | 21 | } |
22 | } | 22 | } |
23 | local map | ||
24 | map = function(arr, action) | ||
25 | local _accum_0 = { } | ||
26 | local _len_0 = 1 | ||
27 | for _index_0 = 1, #arr do | ||
28 | local item = arr[_index_0] | ||
29 | _accum_0[_len_0] = action(item) | ||
30 | _len_0 = _len_0 + 1 | ||
31 | end | ||
32 | return _accum_0 | ||
33 | end | ||
34 | local filter | ||
35 | filter = function(arr, cond) | ||
36 | local _accum_0 = { } | ||
37 | local _len_0 = 1 | ||
38 | for _index_0 = 1, #arr do | ||
39 | local item = arr[_index_0] | ||
40 | if cond(item) then | ||
41 | _accum_0[_len_0] = item | ||
42 | _len_0 = _len_0 + 1 | ||
43 | end | ||
44 | end | ||
45 | return _accum_0 | ||
46 | end | ||
47 | local reduce | ||
48 | reduce = function(arr, init, action) | ||
49 | for _index_0 = 1, #arr do | ||
50 | local item = arr[_index_0] | ||
51 | init = action(init, item) | ||
52 | end | ||
53 | return init | ||
54 | end | ||
23 | print(reduce(filter(map({ | 55 | print(reduce(filter(map({ |
24 | 1, | 56 | 1, |
25 | 2, | 57 | 2, |
@@ -77,6 +109,12 @@ end | |||
77 | print("yuescript") | 109 | print("yuescript") |
78 | print(3) | 110 | print(3) |
79 | print("有效的枚举类型:", "Static") | 111 | print("有效的枚举类型:", "Static") |
112 | do | ||
113 | print(123, "hello") | ||
114 | end | ||
115 | do | ||
116 | print(123, "hello") | ||
117 | end | ||
80 | if tb ~= nil then | 118 | if tb ~= nil then |
81 | tb:func() | 119 | tb:func() |
82 | end | 120 | end |
@@ -177,6 +215,16 @@ for _key_0, _value_0 in pairs(b) do | |||
177 | end | 215 | end |
178 | end | 216 | end |
179 | merge = _tab_0 | 217 | merge = _tab_0 |
218 | local last | ||
219 | do | ||
220 | local _item_0 = data.items | ||
221 | last = _item_0[#_item_0] | ||
222 | end | ||
223 | local second_last | ||
224 | do | ||
225 | local _item_0 = data.items | ||
226 | second_last = _item_0[#_item_0 - 1] | ||
227 | end | ||
180 | local mt = { } | 228 | local mt = { } |
181 | local add | 229 | local add |
182 | add = function(self, right) | 230 | add = function(self, right) |
@@ -307,6 +355,14 @@ func({ | |||
307 | 2, | 355 | 2, |
308 | 3 | 356 | 3 |
309 | }) | 357 | }) |
358 | local f | ||
359 | f = function() | ||
360 | return { | ||
361 | 1, | ||
362 | 2, | ||
363 | 3 | ||
364 | } | ||
365 | end | ||
310 | local tb = { | 366 | local tb = { |
311 | name = "abc", | 367 | name = "abc", |
312 | values = { | 368 | values = { |
@@ -547,6 +603,59 @@ end | |||
547 | local two, four | 603 | local two, four |
548 | local _obj_0 = items | 604 | local _obj_0 = items |
549 | two, four = _obj_0[2], _obj_0[4] | 605 | two, four = _obj_0[2], _obj_0[4] |
606 | local orders = { | ||
607 | "first", | ||
608 | "second", | ||
609 | "third", | ||
610 | "fourth", | ||
611 | "last" | ||
612 | } | ||
613 | local first, bulk, last = orders[1], (function() | ||
614 | local _accum_0 = { } | ||
615 | local _len_0 = 1 | ||
616 | local _max_0 = #orders + -2 + 1 | ||
617 | for _index_0 = 2, _max_0 do | ||
618 | local _item_0 = orders[_index_0] | ||
619 | _accum_0[_len_0] = _item_0 | ||
620 | _len_0 = _len_0 + 1 | ||
621 | end | ||
622 | return _accum_0 | ||
623 | end)(), orders[#orders] | ||
624 | print(first) | ||
625 | print(bulk) | ||
626 | print(last) | ||
627 | local first, rest | ||
628 | do | ||
629 | local _obj_0 = orders | ||
630 | first, rest = _obj_0[1], (function() | ||
631 | local _accum_0 = { } | ||
632 | local _len_0 = 1 | ||
633 | local _max_0 = #_obj_0 | ||
634 | for _index_0 = 2, _max_0 do | ||
635 | local _item_0 = _obj_0[_index_0] | ||
636 | _accum_0[_len_0] = _item_0 | ||
637 | _len_0 = _len_0 + 1 | ||
638 | end | ||
639 | return _accum_0 | ||
640 | end)() | ||
641 | end | ||
642 | local start, last | ||
643 | do | ||
644 | local _obj_0 = orders | ||
645 | start, last = (function() | ||
646 | local _accum_0 = { } | ||
647 | local _len_0 = 1 | ||
648 | local _max_0 = #_obj_0 + -2 + 1 | ||
649 | for _index_0 = 1, _max_0 do | ||
650 | local _item_0 = _obj_0[_index_0] | ||
651 | _accum_0[_len_0] = _item_0 | ||
652 | _len_0 = _len_0 + 1 | ||
653 | end | ||
654 | return _accum_0 | ||
655 | end)(), _obj_0[#_obj_0] | ||
656 | end | ||
657 | local _obj_0 = orders | ||
658 | first, last = _obj_0[1], _obj_0[#_obj_0] | ||
550 | local tuples = { | 659 | local tuples = { |
551 | { | 660 | { |
552 | "hello", | 661 | "hello", |
@@ -648,6 +757,56 @@ end) | |||
648 | if success then | 757 | if success then |
649 | print(result) | 758 | print(result) |
650 | end | 759 | end |
760 | local a, b, c | ||
761 | do | ||
762 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
763 | return func() | ||
764 | end) | ||
765 | if _ok_0 then | ||
766 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
767 | end | ||
768 | end | ||
769 | do | ||
770 | local _exp_0 = ((function() | ||
771 | return (function(_arg_0, ...) | ||
772 | local _ok_0 = _arg_0 | ||
773 | if _ok_0 then | ||
774 | return ... | ||
775 | end | ||
776 | end)(pcall(function() | ||
777 | return func() | ||
778 | end)) | ||
779 | end)()) | ||
780 | if _exp_0 ~= nil then | ||
781 | a = _exp_0 | ||
782 | else | ||
783 | a = "default" | ||
784 | end | ||
785 | end | ||
786 | f((function() | ||
787 | return (function(_arg_0, ...) | ||
788 | local _ok_0 = _arg_0 | ||
789 | if _ok_0 then | ||
790 | return ... | ||
791 | end | ||
792 | end)(pcall(function() | ||
793 | return func() | ||
794 | end)) | ||
795 | end)()) | ||
796 | f((function() | ||
797 | return (function(_arg_0, ...) | ||
798 | local _ok_0 = _arg_0 | ||
799 | if _ok_0 then | ||
800 | return ... | ||
801 | end | ||
802 | end)(xpcall(function() | ||
803 | print(123) | ||
804 | return func() | ||
805 | end, function(e) | ||
806 | print(e) | ||
807 | return e | ||
808 | end)) | ||
809 | end)()) | ||
651 | local a <const> = 123 | 810 | local a <const> = 123 |
652 | local _ <close> = setmetatable({ }, { | 811 | local _ <close> = setmetatable({ }, { |
653 | __close = function() | 812 | __close = function() |
@@ -657,10 +816,19 @@ local _ <close> = setmetatable({ }, { | |||
657 | local a, b, c, d | 816 | local a, b, c, d |
658 | local _obj_0 = tb | 817 | local _obj_0 = tb |
659 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] | 818 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] |
819 | Constant = 123 | ||
660 | local some_string = "这是一个å—符串\n 并包括一个æ¢è¡Œã€‚" | 820 | local some_string = "这是一个å—符串\n 并包括一个æ¢è¡Œã€‚" |
661 | print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") | 821 | print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") |
662 | local integer = 1000000 | 822 | local integer = 1000000 |
663 | local hex = 0xEFBBBF | 823 | local hex = 0xEFBBBF |
824 | local binary = 19 | ||
825 | local str = "key: value\nlist:\n - item1\n - " .. tostring(expr) | ||
826 | local fn | ||
827 | fn = function() | ||
828 | local str = "foo:\n bar: baz" | ||
829 | return str | ||
830 | end | ||
831 | local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'" | ||
664 | local my_function | 832 | local my_function |
665 | my_function = function() end | 833 | my_function = function() end |
666 | my_function() | 834 | my_function() |
@@ -854,11 +1022,10 @@ for i, item in ipairs(items) do | |||
854 | _len_0 = _len_0 + 1 | 1022 | _len_0 = _len_0 + 1 |
855 | end | 1023 | end |
856 | doubled = _accum_0 | 1024 | doubled = _accum_0 |
857 | local iter = ipairs(items) | ||
858 | local slice | 1025 | local slice |
859 | local _accum_0 = { } | 1026 | local _accum_0 = { } |
860 | local _len_0 = 1 | 1027 | local _len_0 = 1 |
861 | for i, item in iter do | 1028 | for i, item in ipairs(items) do |
862 | if i > 1 and i < 3 then | 1029 | if i > 1 and i < 3 then |
863 | _accum_0[_len_0] = item | 1030 | _accum_0[_len_0] = item |
864 | _len_0 = _len_0 + 1 | 1031 | _len_0 = _len_0 + 1 |
@@ -965,8 +1132,7 @@ local slice | |||
965 | local _accum_0 = { } | 1132 | local _accum_0 = { } |
966 | local _len_0 = 1 | 1133 | local _len_0 = 1 |
967 | local _list_0 = items | 1134 | local _list_0 = items |
968 | local _max_0 = 5 | 1135 | for _index_0 = 1, 5 do |
969 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
970 | local item = _list_0[_index_0] | 1136 | local item = _list_0[_index_0] |
971 | _accum_0[_len_0] = item | 1137 | _accum_0[_len_0] = item |
972 | _len_0 = _len_0 + 1 | 1138 | _len_0 = _len_0 + 1 |
@@ -976,7 +1142,8 @@ local slice | |||
976 | local _accum_0 = { } | 1142 | local _accum_0 = { } |
977 | local _len_0 = 1 | 1143 | local _len_0 = 1 |
978 | local _list_0 = items | 1144 | local _list_0 = items |
979 | for _index_0 = 2, #_list_0 do | 1145 | local _max_0 = #_list_0 |
1146 | for _index_0 = 2, _max_0 do | ||
980 | local item = _list_0[_index_0] | 1147 | local item = _list_0[_index_0] |
981 | _accum_0[_len_0] = item | 1148 | _accum_0[_len_0] = item |
982 | _len_0 = _len_0 + 1 | 1149 | _len_0 = _len_0 + 1 |
@@ -986,12 +1153,46 @@ local slice | |||
986 | local _accum_0 = { } | 1153 | local _accum_0 = { } |
987 | local _len_0 = 1 | 1154 | local _len_0 = 1 |
988 | local _list_0 = items | 1155 | local _list_0 = items |
989 | for _index_0 = 1, #_list_0, 2 do | 1156 | local _max_0 = #_list_0 |
1157 | for _index_0 = 1, _max_0, 2 do | ||
990 | local item = _list_0[_index_0] | 1158 | local item = _list_0[_index_0] |
991 | _accum_0[_len_0] = item | 1159 | _accum_0[_len_0] = item |
992 | _len_0 = _len_0 + 1 | 1160 | _len_0 = _len_0 + 1 |
993 | end | 1161 | end |
994 | slice = _accum_0 | 1162 | slice = _accum_0 |
1163 | local slice | ||
1164 | local _accum_0 = { } | ||
1165 | local _len_0 = 1 | ||
1166 | local _list_0 = items | ||
1167 | local _min_0 = #_list_0 + -4 + 1 | ||
1168 | local _max_0 = #_list_0 + -1 + 1 | ||
1169 | for _index_0 = _min_0, _max_0 do | ||
1170 | local item = _list_0[_index_0] | ||
1171 | _accum_0[_len_0] = item | ||
1172 | _len_0 = _len_0 + 1 | ||
1173 | end | ||
1174 | slice = _accum_0 | ||
1175 | local reverse_slice | ||
1176 | local _accum_0 = { } | ||
1177 | local _len_0 = 1 | ||
1178 | local _list_0 = items | ||
1179 | local _min_0 = #_list_0 + -1 + 1 | ||
1180 | for _index_0 = _min_0, 1, -1 do | ||
1181 | local item = _list_0[_index_0] | ||
1182 | _accum_0[_len_0] = item | ||
1183 | _len_0 = _len_0 + 1 | ||
1184 | end | ||
1185 | reverse_slice = _accum_0 | ||
1186 | local sub_list | ||
1187 | local _accum_0 = { } | ||
1188 | local _len_0 = 1 | ||
1189 | local _list_0 = items | ||
1190 | for _index_0 = 2, 4 do | ||
1191 | local _item_0 = _list_0[_index_0] | ||
1192 | _accum_0[_len_0] = _item_0 | ||
1193 | _len_0 = _len_0 + 1 | ||
1194 | end | ||
1195 | sub_list = _accum_0 | ||
995 | for i = 10, 20 do | 1196 | for i = 10, 20 do |
996 | print(i) | 1197 | print(i) |
997 | end | 1198 | end |
@@ -1002,8 +1203,7 @@ for key, value in pairs(object) do | |||
1002 | print(key, value) | 1203 | print(key, value) |
1003 | end | 1204 | end |
1004 | local _list_0 = items | 1205 | local _list_0 = items |
1005 | local _max_0 = 4 | 1206 | for _index_0 = 2, 4 do |
1006 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
1007 | local item = _list_0[_index_0] | 1207 | local item = _list_0[_index_0] |
1008 | print(item) | 1208 | print(item) |
1009 | end | 1209 | end |
@@ -1021,12 +1221,24 @@ local _len_0 = 1 | |||
1021 | for i = 1, 20 do | 1221 | for i = 1, 20 do |
1022 | if i % 2 == 0 then | 1222 | if i % 2 == 0 then |
1023 | _accum_0[_len_0] = i * 2 | 1223 | _accum_0[_len_0] = i * 2 |
1224 | _len_0 = _len_0 + 1 | ||
1024 | else | 1225 | else |
1025 | _accum_0[_len_0] = i | 1226 | _accum_0[_len_0] = i |
1227 | _len_0 = _len_0 + 1 | ||
1026 | end | 1228 | end |
1027 | _len_0 = _len_0 + 1 | ||
1028 | end | 1229 | end |
1029 | doubled_evens = _accum_0 | 1230 | doubled_evens = _accum_0 |
1231 | local first_large | ||
1232 | local _accum_0 | ||
1233 | local _list_0 = numbers | ||
1234 | for _index_0 = 1, #_list_0 do | ||
1235 | local n = _list_0[_index_0] | ||
1236 | if n > 10 then | ||
1237 | _accum_0 = n | ||
1238 | break | ||
1239 | end | ||
1240 | end | ||
1241 | first_large = _accum_0 | ||
1030 | local func_a | 1242 | local func_a |
1031 | func_a = function() | 1243 | func_a = function() |
1032 | for i = 1, 10 do | 1244 | for i = 1, 10 do |
@@ -1175,7 +1387,7 @@ if "Robert" == name then | |||
1175 | elseif "Dan" == name or "Daniel" == name then | 1387 | elseif "Dan" == name or "Daniel" == name then |
1176 | print("ä½ çš„åå—æ˜¯Dan") | 1388 | print("ä½ çš„åå—æ˜¯Dan") |
1177 | else | 1389 | else |
1178 | print("我ä¸çŸ¥é“ä½ çš„åå—") | 1390 | print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„åå—æ˜¯" .. tostring(name)) |
1179 | end | 1391 | end |
1180 | local b = 1 | 1392 | local b = 1 |
1181 | local next_number | 1393 | local next_number |
@@ -1275,6 +1487,192 @@ if _tab_0 then | |||
1275 | end | 1487 | end |
1276 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) | 1488 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) |
1277 | end | 1489 | end |
1490 | local _exp_0 = tb | ||
1491 | local _type_0 = type(_exp_0) | ||
1492 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1493 | local _match_0 = false | ||
1494 | if _tab_0 then | ||
1495 | if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then | ||
1496 | _match_0 = true | ||
1497 | print("1, 2, 3") | ||
1498 | end | ||
1499 | end | ||
1500 | if not _match_0 then | ||
1501 | local _match_1 = false | ||
1502 | if _tab_0 then | ||
1503 | local b = _exp_0[2] | ||
1504 | if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then | ||
1505 | _match_1 = true | ||
1506 | print("1, " .. tostring(b) .. ", 3") | ||
1507 | end | ||
1508 | end | ||
1509 | if not _match_1 then | ||
1510 | if _tab_0 then | ||
1511 | local b = _exp_0[3] | ||
1512 | if b == nil then | ||
1513 | b = 3 | ||
1514 | end | ||
1515 | if 1 == _exp_0[1] and 2 == _exp_0[2] then | ||
1516 | print("1, 2, " .. tostring(b)) | ||
1517 | end | ||
1518 | end | ||
1519 | end | ||
1520 | end | ||
1521 | local _exp_0 = tb | ||
1522 | local _type_0 = type(_exp_0) | ||
1523 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1524 | local _match_0 = false | ||
1525 | if _tab_0 then | ||
1526 | local result = _exp_0.result | ||
1527 | if true == _exp_0.success and result ~= nil then | ||
1528 | _match_0 = true | ||
1529 | print("æˆåŠŸ", result) | ||
1530 | end | ||
1531 | end | ||
1532 | if not _match_0 then | ||
1533 | local _match_1 = false | ||
1534 | if _tab_0 then | ||
1535 | if false == _exp_0.success then | ||
1536 | _match_1 = true | ||
1537 | print("失败", result) | ||
1538 | end | ||
1539 | end | ||
1540 | if not _match_1 then | ||
1541 | print("æ— æ•ˆå€¼") | ||
1542 | end | ||
1543 | end | ||
1544 | local _exp_0 = tb | ||
1545 | local _type_0 = type(_exp_0) | ||
1546 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1547 | local _match_0 = false | ||
1548 | if _tab_0 then | ||
1549 | local content | ||
1550 | do | ||
1551 | local _obj_0 = _exp_0.data | ||
1552 | local _type_1 = type(_obj_0) | ||
1553 | if "table" == _type_1 or "userdata" == _type_1 then | ||
1554 | content = _obj_0.content | ||
1555 | end | ||
1556 | end | ||
1557 | local _val_0 | ||
1558 | do | ||
1559 | local _obj_0 = _exp_0.data | ||
1560 | if _obj_0 ~= nil then | ||
1561 | _val_0 = _obj_0.type | ||
1562 | end | ||
1563 | end | ||
1564 | if "success" == _val_0 and content ~= nil then | ||
1565 | _match_0 = true | ||
1566 | print("æˆåŠŸ", content) | ||
1567 | end | ||
1568 | end | ||
1569 | if not _match_0 then | ||
1570 | local _match_1 = false | ||
1571 | if _tab_0 then | ||
1572 | local content | ||
1573 | do | ||
1574 | local _obj_0 = _exp_0.data | ||
1575 | local _type_1 = type(_obj_0) | ||
1576 | if "table" == _type_1 or "userdata" == _type_1 then | ||
1577 | content = _obj_0.content | ||
1578 | end | ||
1579 | end | ||
1580 | local _val_0 | ||
1581 | do | ||
1582 | local _obj_0 = _exp_0.data | ||
1583 | if _obj_0 ~= nil then | ||
1584 | _val_0 = _obj_0.type | ||
1585 | end | ||
1586 | end | ||
1587 | if "error" == _val_0 and content ~= nil then | ||
1588 | _match_1 = true | ||
1589 | print("失败", content) | ||
1590 | end | ||
1591 | end | ||
1592 | if not _match_1 then | ||
1593 | print("æ— æ•ˆå€¼") | ||
1594 | end | ||
1595 | end | ||
1596 | local _exp_0 = tb | ||
1597 | local _type_0 = type(_exp_0) | ||
1598 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1599 | if _tab_0 then | ||
1600 | local fourth = _exp_0[4] | ||
1601 | local _val_0 | ||
1602 | do | ||
1603 | local _obj_0 = _exp_0[1] | ||
1604 | if _obj_0 ~= nil then | ||
1605 | _val_0 = _obj_0.a | ||
1606 | end | ||
1607 | end | ||
1608 | local _val_1 | ||
1609 | do | ||
1610 | local _obj_0 = _exp_0[1] | ||
1611 | if _obj_0 ~= nil then | ||
1612 | _val_1 = _obj_0.b | ||
1613 | end | ||
1614 | end | ||
1615 | local _val_2 | ||
1616 | do | ||
1617 | local _obj_0 = _exp_0[2] | ||
1618 | if _obj_0 ~= nil then | ||
1619 | _val_2 = _obj_0.a | ||
1620 | end | ||
1621 | end | ||
1622 | local _val_3 | ||
1623 | do | ||
1624 | local _obj_0 = _exp_0[2] | ||
1625 | if _obj_0 ~= nil then | ||
1626 | _val_3 = _obj_0.b | ||
1627 | end | ||
1628 | end | ||
1629 | local _val_4 | ||
1630 | do | ||
1631 | local _obj_0 = _exp_0[3] | ||
1632 | if _obj_0 ~= nil then | ||
1633 | _val_4 = _obj_0.a | ||
1634 | end | ||
1635 | end | ||
1636 | local _val_5 | ||
1637 | do | ||
1638 | local _obj_0 = _exp_0[3] | ||
1639 | if _obj_0 ~= nil then | ||
1640 | _val_5 = _obj_0.b | ||
1641 | end | ||
1642 | end | ||
1643 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then | ||
1644 | print("åŒ¹é…æˆåŠŸ", fourth) | ||
1645 | end | ||
1646 | end | ||
1647 | local segments = { | ||
1648 | "admin", | ||
1649 | "users", | ||
1650 | "logs", | ||
1651 | "view" | ||
1652 | } | ||
1653 | local _type_0 = type(segments) | ||
1654 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
1655 | if _tab_0 then | ||
1656 | local groups | ||
1657 | do | ||
1658 | local _accum_0 = { } | ||
1659 | local _len_0 = 1 | ||
1660 | local _max_0 = #segments + -3 + 1 | ||
1661 | for _index_0 = 1, _max_0 do | ||
1662 | local _item_0 = segments[_index_0] | ||
1663 | _accum_0[_len_0] = _item_0 | ||
1664 | _len_0 = _len_0 + 1 | ||
1665 | end | ||
1666 | groups = _accum_0 | ||
1667 | end | ||
1668 | local resource = segments[#segments - 1] | ||
1669 | local action = segments[#segments] | ||
1670 | if resource ~= nil and action ~= nil then | ||
1671 | print("Group:", groups) | ||
1672 | print("Resource:", resource) | ||
1673 | print("Action:", action) | ||
1674 | end | ||
1675 | end | ||
1278 | local Inventory | 1676 | local Inventory |
1279 | local _class_0 | 1677 | local _class_0 |
1280 | local _base_0 = { | 1678 | local _base_0 = { |
@@ -1931,6 +2329,10 @@ do | |||
1931 | _with_1["key-name"] = value | 2329 | _with_1["key-name"] = value |
1932 | end | 2330 | end |
1933 | _with_0[#_with_0 + 1] = "abc" | 2331 | _with_0[#_with_0 + 1] = "abc" |
2332 | local _with_0 = obj | ||
2333 | if _with_0 ~= nil then | ||
2334 | print(obj.name) | ||
2335 | end | ||
1934 | do | 2336 | do |
1935 | local var = "hello" | 2337 | local var = "hello" |
1936 | print(var) | 2338 | print(var) |
@@ -2021,6 +2423,38 @@ local inventory = { | |||
2021 | } | 2423 | } |
2022 | } | 2424 | } |
2023 | } | 2425 | } |
2426 | local map | ||
2427 | map = function(arr, action) | ||
2428 | local _accum_0 = { } | ||
2429 | local _len_0 = 1 | ||
2430 | for _index_0 = 1, #arr do | ||
2431 | local item = arr[_index_0] | ||
2432 | _accum_0[_len_0] = action(item) | ||
2433 | _len_0 = _len_0 + 1 | ||
2434 | end | ||
2435 | return _accum_0 | ||
2436 | end | ||
2437 | local filter | ||
2438 | filter = function(arr, cond) | ||
2439 | local _accum_0 = { } | ||
2440 | local _len_0 = 1 | ||
2441 | for _index_0 = 1, #arr do | ||
2442 | local item = arr[_index_0] | ||
2443 | if cond(item) then | ||
2444 | _accum_0[_len_0] = item | ||
2445 | _len_0 = _len_0 + 1 | ||
2446 | end | ||
2447 | end | ||
2448 | return _accum_0 | ||
2449 | end | ||
2450 | local reduce | ||
2451 | reduce = function(arr, init, action) | ||
2452 | for _index_0 = 1, #arr do | ||
2453 | local item = arr[_index_0] | ||
2454 | init = action(init, item) | ||
2455 | end | ||
2456 | return init | ||
2457 | end | ||
2024 | print(reduce(filter(map({ | 2458 | print(reduce(filter(map({ |
2025 | 1, | 2459 | 1, |
2026 | 2, | 2460 | 2, |
@@ -2078,6 +2512,12 @@ end | |||
2078 | print("yuescript") | 2512 | print("yuescript") |
2079 | print(3) | 2513 | print(3) |
2080 | print("有效的枚举类型:", "Static") | 2514 | print("有效的枚举类型:", "Static") |
2515 | do | ||
2516 | print(123, "hello") | ||
2517 | end | ||
2518 | do | ||
2519 | print(123, "hello") | ||
2520 | end | ||
2081 | if tb ~= nil then | 2521 | if tb ~= nil then |
2082 | tb:func() | 2522 | tb:func() |
2083 | end | 2523 | end |
@@ -2178,6 +2618,16 @@ for _key_0, _value_0 in pairs(b) do | |||
2178 | end | 2618 | end |
2179 | end | 2619 | end |
2180 | merge = _tab_0 | 2620 | merge = _tab_0 |
2621 | local last | ||
2622 | do | ||
2623 | local _item_0 = data.items | ||
2624 | last = _item_0[#_item_0] | ||
2625 | end | ||
2626 | local second_last | ||
2627 | do | ||
2628 | local _item_0 = data.items | ||
2629 | second_last = _item_0[#_item_0 - 1] | ||
2630 | end | ||
2181 | local mt = { } | 2631 | local mt = { } |
2182 | local add | 2632 | local add |
2183 | add = function(self, right) | 2633 | add = function(self, right) |
@@ -2308,6 +2758,14 @@ func({ | |||
2308 | 2, | 2758 | 2, |
2309 | 3 | 2759 | 3 |
2310 | }) | 2760 | }) |
2761 | local f | ||
2762 | f = function() | ||
2763 | return { | ||
2764 | 1, | ||
2765 | 2, | ||
2766 | 3 | ||
2767 | } | ||
2768 | end | ||
2311 | local tb = { | 2769 | local tb = { |
2312 | name = "abc", | 2770 | name = "abc", |
2313 | values = { | 2771 | values = { |
@@ -2548,6 +3006,59 @@ end | |||
2548 | local two, four | 3006 | local two, four |
2549 | local _obj_0 = items | 3007 | local _obj_0 = items |
2550 | two, four = _obj_0[2], _obj_0[4] | 3008 | two, four = _obj_0[2], _obj_0[4] |
3009 | local orders = { | ||
3010 | "first", | ||
3011 | "second", | ||
3012 | "third", | ||
3013 | "fourth", | ||
3014 | "last" | ||
3015 | } | ||
3016 | local first, bulk, last = orders[1], (function() | ||
3017 | local _accum_0 = { } | ||
3018 | local _len_0 = 1 | ||
3019 | local _max_0 = #orders + -2 + 1 | ||
3020 | for _index_0 = 2, _max_0 do | ||
3021 | local _item_0 = orders[_index_0] | ||
3022 | _accum_0[_len_0] = _item_0 | ||
3023 | _len_0 = _len_0 + 1 | ||
3024 | end | ||
3025 | return _accum_0 | ||
3026 | end)(), orders[#orders] | ||
3027 | print(first) | ||
3028 | print(bulk) | ||
3029 | print(last) | ||
3030 | local first, rest | ||
3031 | do | ||
3032 | local _obj_0 = orders | ||
3033 | first, rest = _obj_0[1], (function() | ||
3034 | local _accum_0 = { } | ||
3035 | local _len_0 = 1 | ||
3036 | local _max_0 = #_obj_0 | ||
3037 | for _index_0 = 2, _max_0 do | ||
3038 | local _item_0 = _obj_0[_index_0] | ||
3039 | _accum_0[_len_0] = _item_0 | ||
3040 | _len_0 = _len_0 + 1 | ||
3041 | end | ||
3042 | return _accum_0 | ||
3043 | end)() | ||
3044 | end | ||
3045 | local start, last | ||
3046 | do | ||
3047 | local _obj_0 = orders | ||
3048 | start, last = (function() | ||
3049 | local _accum_0 = { } | ||
3050 | local _len_0 = 1 | ||
3051 | local _max_0 = #_obj_0 + -2 + 1 | ||
3052 | for _index_0 = 1, _max_0 do | ||
3053 | local _item_0 = _obj_0[_index_0] | ||
3054 | _accum_0[_len_0] = _item_0 | ||
3055 | _len_0 = _len_0 + 1 | ||
3056 | end | ||
3057 | return _accum_0 | ||
3058 | end)(), _obj_0[#_obj_0] | ||
3059 | end | ||
3060 | local _obj_0 = orders | ||
3061 | first, last = _obj_0[1], _obj_0[#_obj_0] | ||
2551 | local tuples = { | 3062 | local tuples = { |
2552 | { | 3063 | { |
2553 | "hello", | 3064 | "hello", |
@@ -2649,6 +3160,56 @@ end) | |||
2649 | if success then | 3160 | if success then |
2650 | print(result) | 3161 | print(result) |
2651 | end | 3162 | end |
3163 | local a, b, c | ||
3164 | do | ||
3165 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
3166 | return func() | ||
3167 | end) | ||
3168 | if _ok_0 then | ||
3169 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
3170 | end | ||
3171 | end | ||
3172 | do | ||
3173 | local _exp_0 = ((function() | ||
3174 | return (function(_arg_0, ...) | ||
3175 | local _ok_0 = _arg_0 | ||
3176 | if _ok_0 then | ||
3177 | return ... | ||
3178 | end | ||
3179 | end)(pcall(function() | ||
3180 | return func() | ||
3181 | end)) | ||
3182 | end)()) | ||
3183 | if _exp_0 ~= nil then | ||
3184 | a = _exp_0 | ||
3185 | else | ||
3186 | a = "default" | ||
3187 | end | ||
3188 | end | ||
3189 | f((function() | ||
3190 | return (function(_arg_0, ...) | ||
3191 | local _ok_0 = _arg_0 | ||
3192 | if _ok_0 then | ||
3193 | return ... | ||
3194 | end | ||
3195 | end)(pcall(function() | ||
3196 | return func() | ||
3197 | end)) | ||
3198 | end)()) | ||
3199 | f((function() | ||
3200 | return (function(_arg_0, ...) | ||
3201 | local _ok_0 = _arg_0 | ||
3202 | if _ok_0 then | ||
3203 | return ... | ||
3204 | end | ||
3205 | end)(xpcall(function() | ||
3206 | print(123) | ||
3207 | return func() | ||
3208 | end, function(e) | ||
3209 | print(e) | ||
3210 | return e | ||
3211 | end)) | ||
3212 | end)()) | ||
2652 | local a <const> = 123 | 3213 | local a <const> = 123 |
2653 | local _ <close> = setmetatable({ }, { | 3214 | local _ <close> = setmetatable({ }, { |
2654 | __close = function() | 3215 | __close = function() |
@@ -2658,10 +3219,19 @@ local _ <close> = setmetatable({ }, { | |||
2658 | local a, b, c, d | 3219 | local a, b, c, d |
2659 | local _obj_0 = tb | 3220 | local _obj_0 = tb |
2660 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] | 3221 | a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] |
3222 | Constant = 123 | ||
2661 | local some_string = "这是一个å—符串\n 并包括一个æ¢è¡Œã€‚" | 3223 | local some_string = "这是一个å—符串\n 并包括一个æ¢è¡Œã€‚" |
2662 | print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") | 3224 | print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") |
2663 | local integer = 1000000 | 3225 | local integer = 1000000 |
2664 | local hex = 0xEFBBBF | 3226 | local hex = 0xEFBBBF |
3227 | local binary = 19 | ||
3228 | local str = "key: value\nlist:\n - item1\n - " .. tostring(expr) | ||
3229 | local fn | ||
3230 | fn = function() | ||
3231 | local str = "foo:\n bar: baz" | ||
3232 | return str | ||
3233 | end | ||
3234 | local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'" | ||
2665 | local my_function | 3235 | local my_function |
2666 | my_function = function() end | 3236 | my_function = function() end |
2667 | my_function() | 3237 | my_function() |
@@ -2855,11 +3425,10 @@ for i, item in ipairs(items) do | |||
2855 | _len_0 = _len_0 + 1 | 3425 | _len_0 = _len_0 + 1 |
2856 | end | 3426 | end |
2857 | doubled = _accum_0 | 3427 | doubled = _accum_0 |
2858 | local iter = ipairs(items) | ||
2859 | local slice | 3428 | local slice |
2860 | local _accum_0 = { } | 3429 | local _accum_0 = { } |
2861 | local _len_0 = 1 | 3430 | local _len_0 = 1 |
2862 | for i, item in iter do | 3431 | for i, item in ipairs(items) do |
2863 | if i > 1 and i < 3 then | 3432 | if i > 1 and i < 3 then |
2864 | _accum_0[_len_0] = item | 3433 | _accum_0[_len_0] = item |
2865 | _len_0 = _len_0 + 1 | 3434 | _len_0 = _len_0 + 1 |
@@ -2966,8 +3535,7 @@ local slice | |||
2966 | local _accum_0 = { } | 3535 | local _accum_0 = { } |
2967 | local _len_0 = 1 | 3536 | local _len_0 = 1 |
2968 | local _list_0 = items | 3537 | local _list_0 = items |
2969 | local _max_0 = 5 | 3538 | for _index_0 = 1, 5 do |
2970 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
2971 | local item = _list_0[_index_0] | 3539 | local item = _list_0[_index_0] |
2972 | _accum_0[_len_0] = item | 3540 | _accum_0[_len_0] = item |
2973 | _len_0 = _len_0 + 1 | 3541 | _len_0 = _len_0 + 1 |
@@ -2977,7 +3545,8 @@ local slice | |||
2977 | local _accum_0 = { } | 3545 | local _accum_0 = { } |
2978 | local _len_0 = 1 | 3546 | local _len_0 = 1 |
2979 | local _list_0 = items | 3547 | local _list_0 = items |
2980 | for _index_0 = 2, #_list_0 do | 3548 | local _max_0 = #_list_0 |
3549 | for _index_0 = 2, _max_0 do | ||
2981 | local item = _list_0[_index_0] | 3550 | local item = _list_0[_index_0] |
2982 | _accum_0[_len_0] = item | 3551 | _accum_0[_len_0] = item |
2983 | _len_0 = _len_0 + 1 | 3552 | _len_0 = _len_0 + 1 |
@@ -2987,12 +3556,46 @@ local slice | |||
2987 | local _accum_0 = { } | 3556 | local _accum_0 = { } |
2988 | local _len_0 = 1 | 3557 | local _len_0 = 1 |
2989 | local _list_0 = items | 3558 | local _list_0 = items |
2990 | for _index_0 = 1, #_list_0, 2 do | 3559 | local _max_0 = #_list_0 |
3560 | for _index_0 = 1, _max_0, 2 do | ||
2991 | local item = _list_0[_index_0] | 3561 | local item = _list_0[_index_0] |
2992 | _accum_0[_len_0] = item | 3562 | _accum_0[_len_0] = item |
2993 | _len_0 = _len_0 + 1 | 3563 | _len_0 = _len_0 + 1 |
2994 | end | 3564 | end |
2995 | slice = _accum_0 | 3565 | slice = _accum_0 |
3566 | local slice | ||
3567 | local _accum_0 = { } | ||
3568 | local _len_0 = 1 | ||
3569 | local _list_0 = items | ||
3570 | local _min_0 = #_list_0 + -4 + 1 | ||
3571 | local _max_0 = #_list_0 + -1 + 1 | ||
3572 | for _index_0 = _min_0, _max_0 do | ||
3573 | local item = _list_0[_index_0] | ||
3574 | _accum_0[_len_0] = item | ||
3575 | _len_0 = _len_0 + 1 | ||
3576 | end | ||
3577 | slice = _accum_0 | ||
3578 | local reverse_slice | ||
3579 | local _accum_0 = { } | ||
3580 | local _len_0 = 1 | ||
3581 | local _list_0 = items | ||
3582 | local _min_0 = #_list_0 + -1 + 1 | ||
3583 | for _index_0 = _min_0, 1, -1 do | ||
3584 | local item = _list_0[_index_0] | ||
3585 | _accum_0[_len_0] = item | ||
3586 | _len_0 = _len_0 + 1 | ||
3587 | end | ||
3588 | reverse_slice = _accum_0 | ||
3589 | local sub_list | ||
3590 | local _accum_0 = { } | ||
3591 | local _len_0 = 1 | ||
3592 | local _list_0 = items | ||
3593 | for _index_0 = 2, 4 do | ||
3594 | local _item_0 = _list_0[_index_0] | ||
3595 | _accum_0[_len_0] = _item_0 | ||
3596 | _len_0 = _len_0 + 1 | ||
3597 | end | ||
3598 | sub_list = _accum_0 | ||
2996 | for i = 10, 20 do | 3599 | for i = 10, 20 do |
2997 | print(i) | 3600 | print(i) |
2998 | end | 3601 | end |
@@ -3003,8 +3606,7 @@ for key, value in pairs(object) do | |||
3003 | print(key, value) | 3606 | print(key, value) |
3004 | end | 3607 | end |
3005 | local _list_0 = items | 3608 | local _list_0 = items |
3006 | local _max_0 = 4 | 3609 | for _index_0 = 2, 4 do |
3007 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | ||
3008 | local item = _list_0[_index_0] | 3610 | local item = _list_0[_index_0] |
3009 | print(item) | 3611 | print(item) |
3010 | end | 3612 | end |
@@ -3022,12 +3624,24 @@ local _len_0 = 1 | |||
3022 | for i = 1, 20 do | 3624 | for i = 1, 20 do |
3023 | if i % 2 == 0 then | 3625 | if i % 2 == 0 then |
3024 | _accum_0[_len_0] = i * 2 | 3626 | _accum_0[_len_0] = i * 2 |
3627 | _len_0 = _len_0 + 1 | ||
3025 | else | 3628 | else |
3026 | _accum_0[_len_0] = i | 3629 | _accum_0[_len_0] = i |
3630 | _len_0 = _len_0 + 1 | ||
3027 | end | 3631 | end |
3028 | _len_0 = _len_0 + 1 | ||
3029 | end | 3632 | end |
3030 | doubled_evens = _accum_0 | 3633 | doubled_evens = _accum_0 |
3634 | local first_large | ||
3635 | local _accum_0 | ||
3636 | local _list_0 = numbers | ||
3637 | for _index_0 = 1, #_list_0 do | ||
3638 | local n = _list_0[_index_0] | ||
3639 | if n > 10 then | ||
3640 | _accum_0 = n | ||
3641 | break | ||
3642 | end | ||
3643 | end | ||
3644 | first_large = _accum_0 | ||
3031 | local func_a | 3645 | local func_a |
3032 | func_a = function() | 3646 | func_a = function() |
3033 | for i = 1, 10 do | 3647 | for i = 1, 10 do |
@@ -3176,7 +3790,7 @@ if "Robert" == name then | |||
3176 | elseif "Dan" == name or "Daniel" == name then | 3790 | elseif "Dan" == name or "Daniel" == name then |
3177 | print("ä½ çš„åå—æ˜¯Dan") | 3791 | print("ä½ çš„åå—æ˜¯Dan") |
3178 | else | 3792 | else |
3179 | print("我ä¸çŸ¥é“ä½ çš„åå—") | 3793 | print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„åå—æ˜¯" .. tostring(name)) |
3180 | end | 3794 | end |
3181 | local b = 1 | 3795 | local b = 1 |
3182 | local next_number | 3796 | local next_number |
@@ -3276,6 +3890,192 @@ if _tab_0 then | |||
3276 | end | 3890 | end |
3277 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) | 3891 | print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) |
3278 | end | 3892 | end |
3893 | local _exp_0 = tb | ||
3894 | local _type_0 = type(_exp_0) | ||
3895 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3896 | local _match_0 = false | ||
3897 | if _tab_0 then | ||
3898 | if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then | ||
3899 | _match_0 = true | ||
3900 | print("1, 2, 3") | ||
3901 | end | ||
3902 | end | ||
3903 | if not _match_0 then | ||
3904 | local _match_1 = false | ||
3905 | if _tab_0 then | ||
3906 | local b = _exp_0[2] | ||
3907 | if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then | ||
3908 | _match_1 = true | ||
3909 | print("1, " .. tostring(b) .. ", 3") | ||
3910 | end | ||
3911 | end | ||
3912 | if not _match_1 then | ||
3913 | if _tab_0 then | ||
3914 | local b = _exp_0[3] | ||
3915 | if b == nil then | ||
3916 | b = 3 | ||
3917 | end | ||
3918 | if 1 == _exp_0[1] and 2 == _exp_0[2] then | ||
3919 | print("1, 2, " .. tostring(b)) | ||
3920 | end | ||
3921 | end | ||
3922 | end | ||
3923 | end | ||
3924 | local _exp_0 = tb | ||
3925 | local _type_0 = type(_exp_0) | ||
3926 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3927 | local _match_0 = false | ||
3928 | if _tab_0 then | ||
3929 | local result = _exp_0.result | ||
3930 | if true == _exp_0.success and result ~= nil then | ||
3931 | _match_0 = true | ||
3932 | print("æˆåŠŸ", result) | ||
3933 | end | ||
3934 | end | ||
3935 | if not _match_0 then | ||
3936 | local _match_1 = false | ||
3937 | if _tab_0 then | ||
3938 | if false == _exp_0.success then | ||
3939 | _match_1 = true | ||
3940 | print("失败", result) | ||
3941 | end | ||
3942 | end | ||
3943 | if not _match_1 then | ||
3944 | print("æ— æ•ˆå€¼") | ||
3945 | end | ||
3946 | end | ||
3947 | local _exp_0 = tb | ||
3948 | local _type_0 = type(_exp_0) | ||
3949 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
3950 | local _match_0 = false | ||
3951 | if _tab_0 then | ||
3952 | local content | ||
3953 | do | ||
3954 | local _obj_0 = _exp_0.data | ||
3955 | local _type_1 = type(_obj_0) | ||
3956 | if "table" == _type_1 or "userdata" == _type_1 then | ||
3957 | content = _obj_0.content | ||
3958 | end | ||
3959 | end | ||
3960 | local _val_0 | ||
3961 | do | ||
3962 | local _obj_0 = _exp_0.data | ||
3963 | if _obj_0 ~= nil then | ||
3964 | _val_0 = _obj_0.type | ||
3965 | end | ||
3966 | end | ||
3967 | if "success" == _val_0 and content ~= nil then | ||
3968 | _match_0 = true | ||
3969 | print("æˆåŠŸ", content) | ||
3970 | end | ||
3971 | end | ||
3972 | if not _match_0 then | ||
3973 | local _match_1 = false | ||
3974 | if _tab_0 then | ||
3975 | local content | ||
3976 | do | ||
3977 | local _obj_0 = _exp_0.data | ||
3978 | local _type_1 = type(_obj_0) | ||
3979 | if "table" == _type_1 or "userdata" == _type_1 then | ||
3980 | content = _obj_0.content | ||
3981 | end | ||
3982 | end | ||
3983 | local _val_0 | ||
3984 | do | ||
3985 | local _obj_0 = _exp_0.data | ||
3986 | if _obj_0 ~= nil then | ||
3987 | _val_0 = _obj_0.type | ||
3988 | end | ||
3989 | end | ||
3990 | if "error" == _val_0 and content ~= nil then | ||
3991 | _match_1 = true | ||
3992 | print("失败", content) | ||
3993 | end | ||
3994 | end | ||
3995 | if not _match_1 then | ||
3996 | print("æ— æ•ˆå€¼") | ||
3997 | end | ||
3998 | end | ||
3999 | local _exp_0 = tb | ||
4000 | local _type_0 = type(_exp_0) | ||
4001 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
4002 | if _tab_0 then | ||
4003 | local fourth = _exp_0[4] | ||
4004 | local _val_0 | ||
4005 | do | ||
4006 | local _obj_0 = _exp_0[1] | ||
4007 | if _obj_0 ~= nil then | ||
4008 | _val_0 = _obj_0.a | ||
4009 | end | ||
4010 | end | ||
4011 | local _val_1 | ||
4012 | do | ||
4013 | local _obj_0 = _exp_0[1] | ||
4014 | if _obj_0 ~= nil then | ||
4015 | _val_1 = _obj_0.b | ||
4016 | end | ||
4017 | end | ||
4018 | local _val_2 | ||
4019 | do | ||
4020 | local _obj_0 = _exp_0[2] | ||
4021 | if _obj_0 ~= nil then | ||
4022 | _val_2 = _obj_0.a | ||
4023 | end | ||
4024 | end | ||
4025 | local _val_3 | ||
4026 | do | ||
4027 | local _obj_0 = _exp_0[2] | ||
4028 | if _obj_0 ~= nil then | ||
4029 | _val_3 = _obj_0.b | ||
4030 | end | ||
4031 | end | ||
4032 | local _val_4 | ||
4033 | do | ||
4034 | local _obj_0 = _exp_0[3] | ||
4035 | if _obj_0 ~= nil then | ||
4036 | _val_4 = _obj_0.a | ||
4037 | end | ||
4038 | end | ||
4039 | local _val_5 | ||
4040 | do | ||
4041 | local _obj_0 = _exp_0[3] | ||
4042 | if _obj_0 ~= nil then | ||
4043 | _val_5 = _obj_0.b | ||
4044 | end | ||
4045 | end | ||
4046 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then | ||
4047 | print("åŒ¹é…æˆåŠŸ", fourth) | ||
4048 | end | ||
4049 | end | ||
4050 | local segments = { | ||
4051 | "admin", | ||
4052 | "users", | ||
4053 | "logs", | ||
4054 | "view" | ||
4055 | } | ||
4056 | local _type_0 = type(segments) | ||
4057 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
4058 | if _tab_0 then | ||
4059 | local groups | ||
4060 | do | ||
4061 | local _accum_0 = { } | ||
4062 | local _len_0 = 1 | ||
4063 | local _max_0 = #segments + -3 + 1 | ||
4064 | for _index_0 = 1, _max_0 do | ||
4065 | local _item_0 = segments[_index_0] | ||
4066 | _accum_0[_len_0] = _item_0 | ||
4067 | _len_0 = _len_0 + 1 | ||
4068 | end | ||
4069 | groups = _accum_0 | ||
4070 | end | ||
4071 | local resource = segments[#segments - 1] | ||
4072 | local action = segments[#segments] | ||
4073 | if resource ~= nil and action ~= nil then | ||
4074 | print("Group:", groups) | ||
4075 | print("Resource:", resource) | ||
4076 | print("Action:", action) | ||
4077 | end | ||
4078 | end | ||
3279 | local Inventory | 4079 | local Inventory |
3280 | local _class_0 | 4080 | local _class_0 |
3281 | local _base_0 = { | 4081 | local _base_0 = { |
@@ -3932,6 +4732,10 @@ do | |||
3932 | _with_1["key-name"] = value | 4732 | _with_1["key-name"] = value |
3933 | end | 4733 | end |
3934 | _with_0[#_with_0 + 1] = "abc" | 4734 | _with_0[#_with_0 + 1] = "abc" |
4735 | local _with_0 = obj | ||
4736 | if _with_0 ~= nil then | ||
4737 | print(obj.name) | ||
4738 | end | ||
3935 | do | 4739 | do |
3936 | local var = "hello" | 4740 | local var = "hello" |
3937 | print(var) | 4741 | print(var) |
diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 9a7c478..663bd44 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua | |||
@@ -243,8 +243,11 @@ end | |||
243 | do | 243 | do |
244 | local _accum_0 = { } | 244 | local _accum_0 = { } |
245 | local _len_0 = 1 | 245 | local _len_0 = 1 |
246 | local _min_0 = 1 + 2 | ||
246 | local _max_0 = 3 + 4 | 247 | local _max_0 = 3 + 4 |
247 | for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 or _max_0 do | 248 | _min_0 = _min_0 < 0 and #items + _min_0 + 1 or _min_0 |
249 | _max_0 = _max_0 < 0 and #items + _max_0 + 1 or _max_0 | ||
250 | for _index_0 = _min_0, _max_0 do | ||
248 | local item = items[_index_0] | 251 | local item = items[_index_0] |
249 | _accum_0[_len_0] = item | 252 | _accum_0[_len_0] = item |
250 | _len_0 = _len_0 + 1 | 253 | _len_0 = _len_0 + 1 |
@@ -254,8 +257,11 @@ end | |||
254 | do | 257 | do |
255 | local _accum_0 = { } | 258 | local _accum_0 = { } |
256 | local _len_0 = 1 | 259 | local _len_0 = 1 |
260 | local _min_0 = hello() * 4 | ||
257 | local _max_0 = 2 - thing[4] | 261 | local _max_0 = 2 - thing[4] |
258 | for _index_0 = hello() * 4, _max_0 < 0 and #items + _max_0 or _max_0 do | 262 | _min_0 = _min_0 < 0 and #items + _min_0 + 1 or _min_0 |
263 | _max_0 = _max_0 < 0 and #items + _max_0 + 1 or _max_0 | ||
264 | for _index_0 = _min_0, _max_0 do | ||
259 | local item = items[_index_0] | 265 | local item = items[_index_0] |
260 | _accum_0[_len_0] = item | 266 | _accum_0[_len_0] = item |
261 | _len_0 = _len_0 + 1 | 267 | _len_0 = _len_0 + 1 |
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 44da58b..ba216b5 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua | |||
@@ -621,4 +621,94 @@ do | |||
621 | print(meta_field, abc, def) | 621 | print(meta_field, abc, def) |
622 | end | 622 | end |
623 | end | 623 | end |
624 | do | ||
625 | local clients = { | ||
626 | "VIP_Alice", | ||
627 | "User_Bob", | ||
628 | "User_Clara", | ||
629 | "VIP_Eva" | ||
630 | } | ||
631 | local vipStart, regulars, vipEnd = clients[1], (function() | ||
632 | local _accum_0 = { } | ||
633 | local _len_0 = 1 | ||
634 | local _max_0 = #clients + -2 + 1 | ||
635 | for _index_0 = 2, _max_0 do | ||
636 | local _item_0 = clients[_index_0] | ||
637 | _accum_0[_len_0] = _item_0 | ||
638 | _len_0 = _len_0 + 1 | ||
639 | end | ||
640 | return _accum_0 | ||
641 | end)(), clients[#clients] | ||
642 | print(vipStart) | ||
643 | print(regulars) | ||
644 | print(vipEnd) | ||
645 | end | ||
646 | do | ||
647 | local setupMeeting | ||
648 | setupMeeting = function(participants) | ||
649 | local chair, secretary = participants[1], participants[#participants] | ||
650 | return print(chair, secretary) | ||
651 | end | ||
652 | setupMeeting({ | ||
653 | "Alice", | ||
654 | "Bob", | ||
655 | "Charlie", | ||
656 | "David" | ||
657 | }) | ||
658 | end | ||
659 | do | ||
660 | local getTransactions | ||
661 | getTransactions = function() | ||
662 | return { | ||
663 | { | ||
664 | id = "T1", | ||
665 | amount = 100 | ||
666 | }, | ||
667 | { | ||
668 | id = "T2", | ||
669 | amount = 200 | ||
670 | }, | ||
671 | { | ||
672 | id = "T3", | ||
673 | amount = 300 | ||
674 | } | ||
675 | } | ||
676 | end | ||
677 | local id, amount | ||
678 | do | ||
679 | local _item_0 = getTransactions() | ||
680 | local _obj_0 = _item_0[#_item_0] | ||
681 | id, amount = _obj_0.id, _obj_0.amount | ||
682 | end | ||
683 | assert(id == "T3") | ||
684 | assert(amount == 300) | ||
685 | end | ||
686 | do | ||
687 | local middle | ||
688 | local _accum_0 = { } | ||
689 | local _len_0 = 1 | ||
690 | local _list_0 = tb | ||
691 | local _max_0 = #_list_0 + -2 + 1 | ||
692 | for _index_0 = 2, _max_0 do | ||
693 | local _item_0 = _list_0[_index_0] | ||
694 | _accum_0[_len_0] = _item_0 | ||
695 | _len_0 = _len_0 + 1 | ||
696 | end | ||
697 | middle = _accum_0 | ||
698 | end | ||
699 | do | ||
700 | local a, abc, b, def, sub, d, e | ||
701 | local _obj_0 = tb | ||
702 | a, abc, b, def, sub, d, e = _obj_0[1], _obj_0.abc, _obj_0[2], _obj_0.def, (function() | ||
703 | local _accum_0 = { } | ||
704 | local _len_0 = 1 | ||
705 | local _max_0 = #_obj_0 + -3 + 1 | ||
706 | for _index_0 = 3, _max_0 do | ||
707 | local _item_0 = _obj_0[_index_0] | ||
708 | _accum_0[_len_0] = _item_0 | ||
709 | _len_0 = _len_0 + 1 | ||
710 | end | ||
711 | return _accum_0 | ||
712 | end)(), _obj_0[#_obj_0 - 1], _obj_0[#_obj_0] | ||
713 | end | ||
624 | return nil | 714 | return nil |
diff --git a/spec/outputs/do.lua b/spec/outputs/do.lua index 6473e03..96d1022 100644 --- a/spec/outputs/do.lua +++ b/spec/outputs/do.lua | |||
@@ -32,10 +32,10 @@ local t = { | |||
32 | } | 32 | } |
33 | return function(y, k) | 33 | return function(y, k) |
34 | if y == nil then | 34 | if y == nil then |
35 | do | 35 | y = ((function() |
36 | x = 10 + 2 | 36 | x = 10 + 2 |
37 | y = x | 37 | return x |
38 | end | 38 | end)()) |
39 | end | 39 | end |
40 | if k == nil then | 40 | if k == nil then |
41 | do | 41 | do |
diff --git a/spec/outputs/global.lua b/spec/outputs/global.lua index 54a21a9..3918f85 100644 --- a/spec/outputs/global.lua +++ b/spec/outputs/global.lua | |||
@@ -93,3 +93,28 @@ do | |||
93 | FooBar = "pascal case" | 93 | FooBar = "pascal case" |
94 | FOOBAR = "all uppercase" | 94 | FOOBAR = "all uppercase" |
95 | end | 95 | end |
96 | do | ||
97 | do | ||
98 | local _class_0 | ||
99 | local _base_0 = { } | ||
100 | if _base_0.__index == nil then | ||
101 | _base_0.__index = _base_0 | ||
102 | end | ||
103 | _class_0 = setmetatable({ | ||
104 | __init = function() end, | ||
105 | __base = _base_0, | ||
106 | __name = "A" | ||
107 | }, { | ||
108 | __index = _base_0, | ||
109 | __call = function(cls, ...) | ||
110 | local _self_0 = setmetatable({ }, _base_0) | ||
111 | cls.__init(_self_0, ...) | ||
112 | return _self_0 | ||
113 | end | ||
114 | }) | ||
115 | _base_0.__class = _class_0 | ||
116 | A = _class_0 | ||
117 | end | ||
118 | Flag = 1 | ||
119 | const, x, y = "const", 1, 2 | ||
120 | end | ||
diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua index 83c99e2..7aa130f 100644 --- a/spec/outputs/import.lua +++ b/spec/outputs/import.lua | |||
@@ -166,3 +166,13 @@ do | |||
166 | local _obj_1 = require("m") | 166 | local _obj_1 = require("m") |
167 | g, i = _obj_1[1], getmetatable(_obj_1[2]).__close | 167 | g, i = _obj_1[1], getmetatable(_obj_1[2]).__close |
168 | end | 168 | end |
169 | do | ||
170 | local require <const> = require | ||
171 | local stringlib <const> = string | ||
172 | local format <const> = string.format | ||
173 | local io_read <const> = io.read | ||
174 | local type | ||
175 | type = function() end | ||
176 | local tp <const> = _G.type | ||
177 | local yue <const> = _G["月"] | ||
178 | end | ||
diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 48ec9c8..2ed7b95 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua | |||
@@ -230,31 +230,36 @@ x = { | |||
230 | 6, | 230 | 6, |
231 | 7 | 231 | 7 |
232 | } | 232 | } |
233 | local _max_0 = -5 | 233 | local _max_0 = #x + -5 + 1 |
234 | for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do | 234 | for _index_0 = 2, _max_0, 2 do |
235 | local y = x[_index_0] | 235 | local y = x[_index_0] |
236 | print(y) | 236 | print(y) |
237 | end | 237 | end |
238 | local _max_1 = 3 | 238 | for _index_0 = 1, 3 do |
239 | for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do | ||
240 | local y = x[_index_0] | 239 | local y = x[_index_0] |
241 | print(y) | 240 | print(y) |
242 | end | 241 | end |
243 | for _index_0 = 2, #x do | 242 | local _max_1 = #x |
243 | for _index_0 = 2, _max_1 do | ||
244 | local y = x[_index_0] | 244 | local y = x[_index_0] |
245 | print(y) | 245 | print(y) |
246 | end | 246 | end |
247 | for _index_0 = 1, #x, 2 do | 247 | local _max_2 = #x |
248 | for _index_0 = 1, _max_2, 2 do | ||
248 | local y = x[_index_0] | 249 | local y = x[_index_0] |
249 | print(y) | 250 | print(y) |
250 | end | 251 | end |
251 | for _index_0 = 2, #x, 2 do | 252 | local _max_3 = #x |
253 | for _index_0 = 2, _max_3, 2 do | ||
252 | local y = x[_index_0] | 254 | local y = x[_index_0] |
253 | print(y) | 255 | print(y) |
254 | end | 256 | end |
255 | local a, b, c = 1, 5, 2 | 257 | local a, b, c = 1, 5, 2 |
256 | local _max_2 = b | 258 | local _min_0 = a |
257 | for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do | 259 | local _max_4 = b |
260 | _min_0 = _min_0 < 0 and #x + _min_0 + 1 or _min_0 | ||
261 | _max_4 = _max_4 < 0 and #x + _max_4 + 1 or _max_4 | ||
262 | for _index_0 = _min_0, _max_4, c do | ||
258 | local y = x[_index_0] | 263 | local y = x[_index_0] |
259 | print(y) | 264 | print(y) |
260 | end | 265 | end |
@@ -287,7 +292,10 @@ do | |||
287 | a | 292 | a |
288 | }) | 293 | }) |
289 | local _list_0 = f | 294 | local _list_0 = f |
290 | for _index_0 = a, #_list_0 do | 295 | local _min_1 = a |
296 | local _max_5 = #_list_0 | ||
297 | _min_1 = _min_1 < 0 and #_list_0 + _min_1 + 1 or _min_1 | ||
298 | for _index_0 = _min_1, _max_5 do | ||
291 | local v = _list_0[_index_0] | 299 | local v = _list_0[_index_0] |
292 | print(v) | 300 | print(v) |
293 | end | 301 | end |
@@ -327,4 +335,191 @@ do | |||
327 | job = "jobless" | 335 | job = "jobless" |
328 | end | 336 | end |
329 | end | 337 | end |
338 | do | ||
339 | local transactions = { | ||
340 | "T001", | ||
341 | "T002", | ||
342 | "T003", | ||
343 | "T004", | ||
344 | "T005" | ||
345 | } | ||
346 | local middleTransactions | ||
347 | do | ||
348 | local _accum_0 = { } | ||
349 | local _len_0 = 1 | ||
350 | local _max_5 = #transactions + -2 + 1 | ||
351 | for _index_0 = 2, _max_5 do | ||
352 | local _item_0 = transactions[_index_0] | ||
353 | _accum_0[_len_0] = _item_0 | ||
354 | _len_0 = _len_0 + 1 | ||
355 | end | ||
356 | middleTransactions = _accum_0 | ||
357 | end | ||
358 | print(middleTransactions) | ||
359 | end | ||
360 | do | ||
361 | local logs = { | ||
362 | { | ||
363 | start = 0, | ||
364 | ["end"] = 100 | ||
365 | }, | ||
366 | { | ||
367 | start = 100, | ||
368 | ["end"] = 200 | ||
369 | }, | ||
370 | { | ||
371 | start = 200, | ||
372 | ["end"] = 123 | ||
373 | } | ||
374 | } | ||
375 | print(logs[#logs]["end"]) | ||
376 | end | ||
377 | do | ||
378 | local pendingOrders = { | ||
379 | "O001", | ||
380 | "O002", | ||
381 | "O003", | ||
382 | "O004" | ||
383 | } | ||
384 | print(pendingOrders[#pendingOrders - 1]) | ||
385 | end | ||
386 | do | ||
387 | local getOrders | ||
388 | getOrders = function() | ||
389 | return { | ||
390 | { | ||
391 | id = "O1001", | ||
392 | status = "pending" | ||
393 | }, | ||
394 | { | ||
395 | id = "O1002", | ||
396 | status = "processing" | ||
397 | }, | ||
398 | { | ||
399 | id = "O1003", | ||
400 | status = "done" | ||
401 | } | ||
402 | } | ||
403 | end | ||
404 | local lastStatus | ||
405 | do | ||
406 | local _item_0 = getOrders() | ||
407 | lastStatus = _item_0[#_item_0].status | ||
408 | end | ||
409 | assert(lastStatus == "done") | ||
410 | end | ||
411 | do | ||
412 | local cloneList1 | ||
413 | cloneList1 = function(list) | ||
414 | local _accum_0 = { } | ||
415 | local _len_0 = 1 | ||
416 | local _max_5 = #list | ||
417 | for _index_0 = 1, _max_5 do | ||
418 | local _item_0 = list[_index_0] | ||
419 | _accum_0[_len_0] = _item_0 | ||
420 | _len_0 = _len_0 + 1 | ||
421 | end | ||
422 | return _accum_0 | ||
423 | end | ||
424 | local cloneList2 | ||
425 | cloneList2 = function(list) | ||
426 | local _tab_0 = { } | ||
427 | local _idx_0 = #_tab_0 + 1 | ||
428 | for _index_0 = 1, #list do | ||
429 | local _value_0 = list[_index_0] | ||
430 | _tab_0[_idx_0] = _value_0 | ||
431 | _idx_0 = _idx_0 + 1 | ||
432 | end | ||
433 | return _tab_0 | ||
434 | end | ||
435 | local cloneTable | ||
436 | cloneTable = function(tb) | ||
437 | local _tab_0 = { } | ||
438 | local _idx_0 = 1 | ||
439 | for _key_0, _value_0 in pairs(tb) do | ||
440 | if _idx_0 == _key_0 then | ||
441 | _tab_0[#_tab_0 + 1] = _value_0 | ||
442 | _idx_0 = _idx_0 + 1 | ||
443 | else | ||
444 | _tab_0[_key_0] = _value_0 | ||
445 | end | ||
446 | end | ||
447 | return _tab_0 | ||
448 | end | ||
449 | end | ||
450 | do | ||
451 | print((function() | ||
452 | local _item_0 = globalTB | ||
453 | return _item_0[#_item_0] | ||
454 | end)(), (function() | ||
455 | local _item_0 = a.b.c | ||
456 | return _item_0[#_item_0 - 2] | ||
457 | end)(), (function() | ||
458 | if x ~= nil then | ||
459 | local _obj_0 = x.y | ||
460 | if _obj_0 ~= nil then | ||
461 | local _obj_1 = _obj_0(x).z | ||
462 | if _obj_1 ~= nil then | ||
463 | return _obj_1[#_obj_1 - 3] | ||
464 | end | ||
465 | return nil | ||
466 | end | ||
467 | return nil | ||
468 | end | ||
469 | return nil | ||
470 | end)()) | ||
471 | end | ||
472 | local _anon_func_0 = function(globalTB) | ||
473 | local _item_0 = globalTB | ||
474 | local _call_0 = _item_0[#_item_0] | ||
475 | return _call_0["end"](_call_0, 123) | ||
476 | end | ||
477 | local _anon_func_1 = function(a) | ||
478 | local _item_0 | ||
479 | do | ||
480 | local _accum_0 = { } | ||
481 | local _len_0 = 1 | ||
482 | local _list_0 = a.b.c | ||
483 | local _max_5 = #_list_0 + -5 + 1 | ||
484 | for _index_0 = 5, _max_5 do | ||
485 | local _item_1 = _list_0[_index_0] | ||
486 | _accum_0[_len_0] = _item_1 | ||
487 | _len_0 = _len_0 + 1 | ||
488 | end | ||
489 | _item_0 = _accum_0 | ||
490 | end | ||
491 | return _item_0[#_item_0 - 2] | ||
492 | end | ||
493 | local _anon_func_2 = function(x) | ||
494 | if x ~= nil then | ||
495 | local _obj_0 = x.y | ||
496 | if _obj_0 ~= nil then | ||
497 | local _obj_1 = _obj_0(x).z | ||
498 | if _obj_1 ~= nil then | ||
499 | local _obj_2 = _obj_1[#_obj_1 - 3] | ||
500 | if _obj_2 ~= nil then | ||
501 | local _accum_0 = { } | ||
502 | local _len_0 = 1 | ||
503 | local _max_5 = #_obj_2 + -3 + 1 | ||
504 | for _index_0 = 1, _max_5 do | ||
505 | local _item_0 = _obj_2[_index_0] | ||
506 | _accum_0[_len_0] = _item_0 | ||
507 | _len_0 = _len_0 + 1 | ||
508 | end | ||
509 | return _accum_0 | ||
510 | end | ||
511 | return nil | ||
512 | end | ||
513 | return nil | ||
514 | end | ||
515 | return nil | ||
516 | end | ||
517 | return nil | ||
518 | end | ||
519 | do | ||
520 | local f | ||
521 | f = function() | ||
522 | return print(_anon_func_0(globalTB), _anon_func_1(a), _anon_func_2(x)) | ||
523 | end | ||
524 | end | ||
330 | return nil | 525 | return nil |
diff --git a/spec/outputs/literals.lua b/spec/outputs/literals.lua index a578d58..6de5411 100644 --- a/spec/outputs/literals.lua +++ b/spec/outputs/literals.lua | |||
@@ -8,10 +8,18 @@ local _ = { | |||
8 | 0xfF2323, | 8 | 0xfF2323, |
9 | 0xabcdef, | 9 | 0xabcdef, |
10 | 0xABCDEF, | 10 | 0xABCDEF, |
11 | 0XFBC400, | ||
11 | 0x123p-123, | 12 | 0x123p-123, |
12 | 0xABCP+321, | 13 | 0xABCP+321, |
13 | 0x.1p-111, | 14 | 0x.1p-111, |
14 | 0xABCP-321, | 15 | 0xABCP-321, |
16 | 0x0.1E, | ||
17 | 0xA23p-4, | ||
18 | 0X1.921FB54442D18P+1, | ||
19 | 1, | ||
20 | 8, | ||
21 | 15, | ||
22 | 201, | ||
15 | .2323, | 23 | .2323, |
16 | .2323e-1, | 24 | .2323e-1, |
17 | .2323e13434, | 25 | .2323e13434, |
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 8624d49..6ab4bbb 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua | |||
@@ -60,8 +60,8 @@ do | |||
60 | local y = hello[_index_0] | 60 | local y = hello[_index_0] |
61 | if y % 2 == 0 then | 61 | if y % 2 == 0 then |
62 | _accum_0[_len_0] = y | 62 | _accum_0[_len_0] = y |
63 | _len_0 = _len_0 + 1 | ||
63 | end | 64 | end |
64 | _len_0 = _len_0 + 1 | ||
65 | end | 65 | end |
66 | x = _accum_0 | 66 | x = _accum_0 |
67 | end | 67 | end |
@@ -132,13 +132,11 @@ do | |||
132 | end | 132 | end |
133 | do | 133 | do |
134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
135 | local _len_0 = 1 | ||
136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
138 | local thing = _list_2[_index_0] | 137 | local thing = _list_2[_index_0] |
139 | y = "hello" | 138 | y = "hello" |
140 | break | 139 | break |
141 | _len_0 = _len_0 + 1 | ||
142 | end | 140 | end |
143 | x = _accum_0 | 141 | x = _accum_0 |
144 | end | 142 | end |
@@ -370,3 +368,131 @@ do | |||
370 | end | 368 | end |
371 | until false | 369 | until false |
372 | end | 370 | end |
371 | local _anon_func_0 = function(i, tb) | ||
372 | local _accum_0 = { } | ||
373 | local _len_0 = 1 | ||
374 | while tb[i] do | ||
375 | i = i + 1 | ||
376 | _accum_0[_len_0] = i - 1 | ||
377 | _len_0 = _len_0 + 1 | ||
378 | end | ||
379 | return _accum_0 | ||
380 | end | ||
381 | do | ||
382 | local index | ||
383 | do | ||
384 | local _accum_0 | ||
385 | for i = 1, #tb do | ||
386 | if tb[i] then | ||
387 | _accum_0 = i | ||
388 | break | ||
389 | end | ||
390 | end | ||
391 | index = _accum_0 | ||
392 | end | ||
393 | f((function() | ||
394 | local _accum_0 | ||
395 | for i = 1, #tb do | ||
396 | if tb[i] then | ||
397 | _accum_0 = i | ||
398 | break | ||
399 | end | ||
400 | end | ||
401 | return _accum_0 | ||
402 | end)()) | ||
403 | f((function() | ||
404 | local _accum_0 = { } | ||
405 | local _len_0 = 1 | ||
406 | for i = 1, #tb do | ||
407 | if tb[i] then | ||
408 | _accum_0[_len_0] = i | ||
409 | _len_0 = _len_0 + 1 | ||
410 | end | ||
411 | end | ||
412 | return _accum_0 | ||
413 | end)()) | ||
414 | i = 1 | ||
415 | local ids | ||
416 | do | ||
417 | local _accum_0 = { } | ||
418 | local _len_0 = 1 | ||
419 | while tb[i] do | ||
420 | i = i + 1 | ||
421 | _accum_0[_len_0] = i - 1 | ||
422 | _len_0 = _len_0 + 1 | ||
423 | end | ||
424 | ids = _accum_0 | ||
425 | end | ||
426 | i = 1 | ||
427 | local idx | ||
428 | do | ||
429 | local _accum_0 | ||
430 | while tb[i] do | ||
431 | i = i + 1 | ||
432 | _accum_0 = i - 1 | ||
433 | break | ||
434 | end | ||
435 | idx = _accum_0 | ||
436 | end | ||
437 | local f1 | ||
438 | f1 = function() | ||
439 | i = 1 | ||
440 | return f(_anon_func_0(i, tb)) | ||
441 | end | ||
442 | i = 1 | ||
443 | f((function() | ||
444 | local _accum_0 | ||
445 | while tb[i] do | ||
446 | i = i + 1 | ||
447 | _accum_0 = i - 1 | ||
448 | break | ||
449 | end | ||
450 | return _accum_0 | ||
451 | end)()) | ||
452 | local _accum_0 = { } | ||
453 | local _len_0 = 1 | ||
454 | local _list_3 = items | ||
455 | for _index_0 = 1, #_list_3 do | ||
456 | local item = _list_3[_index_0] | ||
457 | local _type_0 = type(item) | ||
458 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
459 | if _tab_0 then | ||
460 | local value = item.value | ||
461 | if "A" == item.type and value ~= nil then | ||
462 | if value > 5 then | ||
463 | _accum_0[_len_0] = item | ||
464 | _len_0 = _len_0 + 1 | ||
465 | end | ||
466 | end | ||
467 | end | ||
468 | end | ||
469 | list = _accum_0 | ||
470 | end | ||
471 | do | ||
472 | repeat | ||
473 | print(1) | ||
474 | until true | ||
475 | do | ||
476 | local _accum_0 | ||
477 | repeat | ||
478 | a = func() | ||
479 | _accum_0 = a.x | ||
480 | break | ||
481 | until a.v | ||
482 | x = _accum_0 | ||
483 | end | ||
484 | local items | ||
485 | local _accum_0 = { } | ||
486 | local _len_0 = 1 | ||
487 | repeat | ||
488 | local item = getItem() | ||
489 | if not item then | ||
490 | break | ||
491 | end | ||
492 | if item.value > 0 then | ||
493 | _accum_0[_len_0] = item | ||
494 | _len_0 = _len_0 + 1 | ||
495 | end | ||
496 | until false | ||
497 | items = _accum_0 | ||
498 | end | ||
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua index 4d31574..89c6e63 100644 --- a/spec/outputs/macro.lua +++ b/spec/outputs/macro.lua | |||
@@ -26,6 +26,10 @@ print({ | |||
26 | 123, | 26 | 123, |
27 | 'xyz' | 27 | 'xyz' |
28 | }) | 28 | }) |
29 | print({ | ||
30 | 456, | ||
31 | 'abc' | ||
32 | }) | ||
29 | do | 33 | do |
30 | assert(item == nil) | 34 | assert(item == nil) |
31 | end | 35 | end |
@@ -213,6 +217,13 @@ function tb:func() | |||
213 | end | 217 | end |
214 | end | 218 | end |
215 | print(x) | 219 | print(x) |
220 | local yue = require("yue") | ||
221 | do | ||
222 | local function f2(a) | ||
223 | return a + 1 | ||
224 | end | ||
225 | x = x + f2(3) | ||
226 | end | ||
216 | local sel | 227 | local sel |
217 | sel = function(a, b, c) | 228 | sel = function(a, b, c) |
218 | if a then | 229 | if a then |
@@ -317,7 +328,7 @@ print((setmetatable({ | |||
317 | return 998 | 328 | return 998 |
318 | end | 329 | end |
319 | })) | 330 | })) |
320 | print("current line: " .. tostring(323)) | 331 | print("current line: " .. tostring(349)) |
321 | do | 332 | do |
322 | do | 333 | do |
323 | -- TODO | 334 | -- TODO |
@@ -330,10 +341,8 @@ local _1 | |||
330 | _1 = function() | 341 | _1 = function() |
331 | print(1) | 342 | print(1) |
332 | local _accum_0 = { } | 343 | local _accum_0 = { } |
333 | local _len_0 = 1 | ||
334 | while false do | 344 | while false do |
335 | break | 345 | break |
336 | _len_0 = _len_0 + 1 | ||
337 | end | 346 | end |
338 | return _accum_0 | 347 | return _accum_0 |
339 | end | 348 | end |
diff --git a/spec/outputs/props.lua b/spec/outputs/props.lua new file mode 100644 index 0000000..2c282e0 --- /dev/null +++ b/spec/outputs/props.lua | |||
@@ -0,0 +1,240 @@ | |||
1 | local Props | ||
2 | do | ||
3 | local _class_0 | ||
4 | local assignReadOnly | ||
5 | local _base_0 = { | ||
6 | __index = function(self, name) | ||
7 | local cls = getmetatable(self) | ||
8 | do | ||
9 | local item | ||
10 | do | ||
11 | local _obj_0 = cls.__getter | ||
12 | if _obj_0 ~= nil then | ||
13 | item = _obj_0[name] | ||
14 | end | ||
15 | end | ||
16 | if item then | ||
17 | return item(self) | ||
18 | else | ||
19 | item = rawget(cls, name) | ||
20 | if item then | ||
21 | return item | ||
22 | else | ||
23 | local c = cls | ||
24 | repeat | ||
25 | c = getmetatable(c) | ||
26 | if c then | ||
27 | local _obj_0 = c.__getter | ||
28 | if _obj_0 ~= nil then | ||
29 | item = _obj_0[name] | ||
30 | end | ||
31 | if item then | ||
32 | if cls.__getter == nil then | ||
33 | cls.__getter = { } | ||
34 | end | ||
35 | cls.__getter[name] = item | ||
36 | return item(self) | ||
37 | else | ||
38 | item = rawget(c, name) | ||
39 | if item then | ||
40 | rawset(cls, name, item) | ||
41 | return item | ||
42 | end | ||
43 | end | ||
44 | else | ||
45 | break | ||
46 | end | ||
47 | until false | ||
48 | end | ||
49 | end | ||
50 | end | ||
51 | return nil | ||
52 | end, | ||
53 | __newindex = function(self, name, value) | ||
54 | local cls = getmetatable(self) | ||
55 | local item | ||
56 | local _obj_0 = cls.__setter | ||
57 | if _obj_0 ~= nil then | ||
58 | item = _obj_0[name] | ||
59 | end | ||
60 | if item then | ||
61 | return item(self, value) | ||
62 | else | ||
63 | local c = cls | ||
64 | repeat | ||
65 | c = getmetatable(c) | ||
66 | if c then | ||
67 | local _obj_1 = c.__setter | ||
68 | if _obj_1 ~= nil then | ||
69 | item = _obj_1[name] | ||
70 | end | ||
71 | if item then | ||
72 | if cls.__setter == nil then | ||
73 | cls.__setter = { } | ||
74 | end | ||
75 | cls.__setter[name] = item | ||
76 | item(self, value) | ||
77 | return | ||
78 | end | ||
79 | else | ||
80 | break | ||
81 | end | ||
82 | until false | ||
83 | return rawset(self, name, value) | ||
84 | end | ||
85 | end, | ||
86 | prop = function(self, name, props) | ||
87 | local get, set = props.get, props.set | ||
88 | if set == nil then | ||
89 | set = assignReadOnly | ||
90 | end | ||
91 | do | ||
92 | local getter = rawget(self.__base, "__getter") | ||
93 | if getter then | ||
94 | getter[name] = get | ||
95 | else | ||
96 | rawset(self.__base, "__getter", { | ||
97 | [name] = get | ||
98 | }) | ||
99 | end | ||
100 | end | ||
101 | local setter = rawget(self.__base, "__setter") | ||
102 | if setter then | ||
103 | setter[name] = set | ||
104 | else | ||
105 | return rawset(self.__base, "__setter", { | ||
106 | [name] = set | ||
107 | }) | ||
108 | end | ||
109 | end | ||
110 | } | ||
111 | if _base_0.__index == nil then | ||
112 | _base_0.__index = _base_0 | ||
113 | end | ||
114 | _class_0 = setmetatable({ | ||
115 | __init = function() end, | ||
116 | __base = _base_0, | ||
117 | __name = "Props" | ||
118 | }, { | ||
119 | __index = _base_0, | ||
120 | __call = function(cls, ...) | ||
121 | local _self_0 = setmetatable({ }, _base_0) | ||
122 | cls.__init(_self_0, ...) | ||
123 | return _self_0 | ||
124 | end | ||
125 | }) | ||
126 | _base_0.__class = _class_0 | ||
127 | local self = _class_0; | ||
128 | assignReadOnly = function() | ||
129 | return error("assigning a readonly property") | ||
130 | end | ||
131 | Props = _class_0 | ||
132 | end | ||
133 | local A | ||
134 | do | ||
135 | local _class_0 | ||
136 | local _parent_0 = Props | ||
137 | local _base_0 = { } | ||
138 | for _key_0, _val_0 in pairs(_parent_0.__base) do | ||
139 | if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then | ||
140 | _base_0[_key_0] = _val_0 | ||
141 | end | ||
142 | end | ||
143 | if _base_0.__index == nil then | ||
144 | _base_0.__index = _base_0 | ||
145 | end | ||
146 | setmetatable(_base_0, _parent_0.__base) | ||
147 | _class_0 = setmetatable({ | ||
148 | __init = function(self) | ||
149 | self._x = 0 | ||
150 | end, | ||
151 | __base = _base_0, | ||
152 | __name = "A", | ||
153 | __parent = _parent_0 | ||
154 | }, { | ||
155 | __index = function(cls, name) | ||
156 | local val = rawget(_base_0, name) | ||
157 | if val == nil then | ||
158 | local parent = rawget(cls, "__parent") | ||
159 | if parent then | ||
160 | return parent[name] | ||
161 | end | ||
162 | else | ||
163 | return val | ||
164 | end | ||
165 | end, | ||
166 | __call = function(cls, ...) | ||
167 | local _self_0 = setmetatable({ }, _base_0) | ||
168 | cls.__init(_self_0, ...) | ||
169 | return _self_0 | ||
170 | end | ||
171 | }) | ||
172 | _base_0.__class = _class_0 | ||
173 | local self = _class_0; | ||
174 | self:prop('x', { | ||
175 | get = function(self) | ||
176 | return self._x + 1000 | ||
177 | end, | ||
178 | set = function(self, v) | ||
179 | self._x = v | ||
180 | end | ||
181 | }) | ||
182 | if _parent_0.__inherited then | ||
183 | _parent_0.__inherited(_parent_0, _class_0) | ||
184 | end | ||
185 | A = _class_0 | ||
186 | end | ||
187 | local B | ||
188 | do | ||
189 | local _class_0 | ||
190 | local _parent_0 = A | ||
191 | local _base_0 = { } | ||
192 | for _key_0, _val_0 in pairs(_parent_0.__base) do | ||
193 | if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then | ||
194 | _base_0[_key_0] = _val_0 | ||
195 | end | ||
196 | end | ||
197 | if _base_0.__index == nil then | ||
198 | _base_0.__index = _base_0 | ||
199 | end | ||
200 | setmetatable(_base_0, _parent_0.__base) | ||
201 | _class_0 = setmetatable({ | ||
202 | __init = function(self, ...) | ||
203 | return _class_0.__parent.__init(self, ...) | ||
204 | end, | ||
205 | __base = _base_0, | ||
206 | __name = "B", | ||
207 | __parent = _parent_0 | ||
208 | }, { | ||
209 | __index = function(cls, name) | ||
210 | local val = rawget(_base_0, name) | ||
211 | if val == nil then | ||
212 | local parent = rawget(cls, "__parent") | ||
213 | if parent then | ||
214 | return parent[name] | ||
215 | end | ||
216 | else | ||
217 | return val | ||
218 | end | ||
219 | end, | ||
220 | __call = function(cls, ...) | ||
221 | local _self_0 = setmetatable({ }, _base_0) | ||
222 | cls.__init(_self_0, ...) | ||
223 | return _self_0 | ||
224 | end | ||
225 | }) | ||
226 | _base_0.__class = _class_0 | ||
227 | local self = _class_0; | ||
228 | self:prop('abc', { | ||
229 | get = function(self) | ||
230 | return "hello" | ||
231 | end | ||
232 | }) | ||
233 | if _parent_0.__inherited then | ||
234 | _parent_0.__inherited(_parent_0, _class_0) | ||
235 | end | ||
236 | B = _class_0 | ||
237 | end | ||
238 | local b = B() | ||
239 | b.x = 999 | ||
240 | return print(b.x, b.abc) | ||
diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index febea62..b536e6d 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua | |||
@@ -1,3 +1,4 @@ | |||
1 | local _module_0 = { } | ||
1 | local hi = "hello" | 2 | local hi = "hello" |
2 | local hello = "what the heckyes" | 3 | local hello = "what the heckyes" |
3 | print(hi) | 4 | print(hi) |
@@ -41,4 +42,42 @@ local _ = "hello"; | |||
41 | ("hello"):format().hello(1, 2, 3); | 42 | ("hello"):format().hello(1, 2, 3); |
42 | ("hello"):format(1, 2, 3) | 43 | ("hello"):format(1, 2, 3) |
43 | something("hello"):world() | 44 | something("hello"):world() |
44 | return something(("hello"):world()) | 45 | something(("hello"):world()) |
46 | do | ||
47 | local str = "key: value" | ||
48 | str = "config:\n\tenabled: true\n\tlevel: 5" | ||
49 | str = "header: start\nfooter: end" | ||
50 | str = "name: " .. tostring(username) | ||
51 | str = "count: " .. tostring(total) .. " items" | ||
52 | str = "user: " .. tostring(name) .. "\nid: " .. tostring(id) | ||
53 | str = "path: \"C:\\\\Program Files\\\\App\"\ndesc: 'single \"quote\" test'" | ||
54 | str = "key: value \nnext: 123 " | ||
55 | str = "list:\n - \"one\"\n - \"two\"" | ||
56 | str = "-- comment\ncontent text\n-- comment" | ||
57 | str = tostring(1 + 2) .. '\n' .. tostring(2 + 3) .. '\n' .. tostring("a" .. "b") | ||
58 | local obj = { | ||
59 | settings = "mode: " .. tostring(mode) .. "\nflags:\n\t- " .. tostring(flag1) .. "\n\t- default" | ||
60 | } | ||
61 | local fn | ||
62 | fn = function() | ||
63 | return "Hello\nname: " .. tostring(userName) | ||
64 | end | ||
65 | str = "result:\n\tstatus: " .. tostring((function() | ||
66 | if ok then | ||
67 | return "pass" | ||
68 | else | ||
69 | return "fail" | ||
70 | end | ||
71 | end)()) .. "\n\tcode: " .. tostring(code) | ||
72 | local summary = "date: " .. tostring(os.date()) .. "\nvalues:\n\t-\n\t\ta: " .. tostring(aVal) .. "\n\t\tb: " .. tostring(bVal or defaultB) | ||
73 | local msg = send("Hello, " .. tostring(user) .. "!\nToday is " .. tostring(os.date("%A")) .. ".") | ||
74 | local desc | ||
75 | do | ||
76 | local prefix = "Result" | ||
77 | desc = tostring(prefix) .. ":\nvalue: " .. tostring(compute()) | ||
78 | end | ||
79 | print(("1\n2\n3")) | ||
80 | end | ||
81 | local yaml = "version: " .. tostring(ver) .. "\nok: true" | ||
82 | _module_0["yaml"] = yaml | ||
83 | return _module_0 | ||
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua index e4dedc9..7c1004b 100644 --- a/spec/outputs/switch.lua +++ b/spec/outputs/switch.lua | |||
@@ -415,4 +415,366 @@ do | |||
415 | end | 415 | end |
416 | end | 416 | end |
417 | end | 417 | end |
418 | do | ||
419 | local _exp_0 = tb | ||
420 | local _type_0 = type(_exp_0) | ||
421 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
422 | local _match_0 = false | ||
423 | if _tab_0 then | ||
424 | if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then | ||
425 | _match_0 = true | ||
426 | print("1, 2, 3") | ||
427 | end | ||
428 | end | ||
429 | if not _match_0 then | ||
430 | local _match_1 = false | ||
431 | if _tab_0 then | ||
432 | local b = _exp_0[2] | ||
433 | if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then | ||
434 | _match_1 = true | ||
435 | print("1, " .. tostring(b) .. ", 3") | ||
436 | end | ||
437 | end | ||
438 | if not _match_1 then | ||
439 | if _tab_0 then | ||
440 | local b = _exp_0[3] | ||
441 | if b == nil then | ||
442 | b = 3 | ||
443 | end | ||
444 | if 1 == _exp_0[1] and 2 == _exp_0[2] then | ||
445 | print("1, 2, " .. tostring(b)) | ||
446 | end | ||
447 | end | ||
448 | end | ||
449 | end | ||
450 | end | ||
451 | do | ||
452 | local _exp_0 = tb | ||
453 | local _type_0 = type(_exp_0) | ||
454 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
455 | local _match_0 = false | ||
456 | if _tab_0 then | ||
457 | local result = _exp_0.result | ||
458 | if true == _exp_0.success and result ~= nil then | ||
459 | _match_0 = true | ||
460 | print("success", result) | ||
461 | end | ||
462 | end | ||
463 | if not _match_0 then | ||
464 | local _match_1 = false | ||
465 | if _tab_0 then | ||
466 | if false == _exp_0.success then | ||
467 | _match_1 = true | ||
468 | print("failed", result) | ||
469 | end | ||
470 | end | ||
471 | if not _match_1 then | ||
472 | print("invalid") | ||
473 | end | ||
474 | end | ||
475 | end | ||
476 | do | ||
477 | local _exp_0 = tb | ||
478 | local _type_0 = type(_exp_0) | ||
479 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
480 | local _match_0 = false | ||
481 | if _tab_0 then | ||
482 | local content = _exp_0.content | ||
483 | if "success" == _exp_0.type and content ~= nil then | ||
484 | _match_0 = true | ||
485 | print("success", content) | ||
486 | end | ||
487 | end | ||
488 | if not _match_0 then | ||
489 | local _match_1 = false | ||
490 | if _tab_0 then | ||
491 | local content = _exp_0.content | ||
492 | if "error" == _exp_0.type and content ~= nil then | ||
493 | _match_1 = true | ||
494 | print("failed", content) | ||
495 | end | ||
496 | end | ||
497 | if not _match_1 then | ||
498 | print("invalid") | ||
499 | end | ||
500 | end | ||
501 | end | ||
502 | do | ||
503 | do | ||
504 | local _exp_0 = tb | ||
505 | local _type_0 = type(_exp_0) | ||
506 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
507 | if _tab_0 then | ||
508 | local fourth = _exp_0[4] | ||
509 | local _val_0 | ||
510 | do | ||
511 | local _obj_0 = _exp_0[1] | ||
512 | if _obj_0 ~= nil then | ||
513 | _val_0 = _obj_0.a | ||
514 | end | ||
515 | end | ||
516 | local _val_1 | ||
517 | do | ||
518 | local _obj_0 = _exp_0[1] | ||
519 | if _obj_0 ~= nil then | ||
520 | _val_1 = _obj_0.b | ||
521 | end | ||
522 | end | ||
523 | local _val_2 | ||
524 | do | ||
525 | local _obj_0 = _exp_0[2] | ||
526 | if _obj_0 ~= nil then | ||
527 | _val_2 = _obj_0.a | ||
528 | end | ||
529 | end | ||
530 | local _val_3 | ||
531 | do | ||
532 | local _obj_0 = _exp_0[2] | ||
533 | if _obj_0 ~= nil then | ||
534 | _val_3 = _obj_0.b | ||
535 | end | ||
536 | end | ||
537 | local _val_4 | ||
538 | do | ||
539 | local _obj_0 = _exp_0[3] | ||
540 | if _obj_0 ~= nil then | ||
541 | _val_4 = _obj_0.a | ||
542 | end | ||
543 | end | ||
544 | local _val_5 | ||
545 | do | ||
546 | local _obj_0 = _exp_0[3] | ||
547 | if _obj_0 ~= nil then | ||
548 | _val_5 = _obj_0.b | ||
549 | end | ||
550 | end | ||
551 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then | ||
552 | print("matched", fourth) | ||
553 | end | ||
554 | end | ||
555 | end | ||
556 | local _exp_0 = tb | ||
557 | local _type_0 = type(_exp_0) | ||
558 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
559 | local _match_0 = false | ||
560 | if _tab_0 then | ||
561 | local _val_0 | ||
562 | do | ||
563 | local _obj_0 = _exp_0[1] | ||
564 | if _obj_0 ~= nil then | ||
565 | _val_0 = _obj_0.c | ||
566 | end | ||
567 | end | ||
568 | local _val_1 | ||
569 | do | ||
570 | local _obj_0 = _exp_0[1] | ||
571 | if _obj_0 ~= nil then | ||
572 | _val_1 = _obj_0.d | ||
573 | end | ||
574 | end | ||
575 | local _val_2 | ||
576 | do | ||
577 | local _obj_0 = _exp_0[2] | ||
578 | if _obj_0 ~= nil then | ||
579 | _val_2 = _obj_0.c | ||
580 | end | ||
581 | end | ||
582 | local _val_3 | ||
583 | do | ||
584 | local _obj_0 = _exp_0[2] | ||
585 | if _obj_0 ~= nil then | ||
586 | _val_3 = _obj_0.d | ||
587 | end | ||
588 | end | ||
589 | local _val_4 | ||
590 | do | ||
591 | local _obj_0 = _exp_0[3] | ||
592 | if _obj_0 ~= nil then | ||
593 | _val_4 = _obj_0.c | ||
594 | end | ||
595 | end | ||
596 | local _val_5 | ||
597 | do | ||
598 | local _obj_0 = _exp_0[3] | ||
599 | if _obj_0 ~= nil then | ||
600 | _val_5 = _obj_0.d | ||
601 | end | ||
602 | end | ||
603 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 then | ||
604 | _match_0 = true | ||
605 | print("OK") | ||
606 | end | ||
607 | end | ||
608 | if not _match_0 then | ||
609 | if _tab_0 then | ||
610 | local sixth = _exp_0[6] | ||
611 | local _val_0 | ||
612 | do | ||
613 | local _obj_0 = _exp_0[3] | ||
614 | if _obj_0 ~= nil then | ||
615 | _val_0 = _obj_0.a | ||
616 | end | ||
617 | end | ||
618 | local _val_1 | ||
619 | do | ||
620 | local _obj_0 = _exp_0[3] | ||
621 | if _obj_0 ~= nil then | ||
622 | _val_1 = _obj_0.b | ||
623 | end | ||
624 | end | ||
625 | local _val_2 | ||
626 | do | ||
627 | local _obj_0 = _exp_0[4] | ||
628 | if _obj_0 ~= nil then | ||
629 | _val_2 = _obj_0.a | ||
630 | end | ||
631 | end | ||
632 | local _val_3 | ||
633 | do | ||
634 | local _obj_0 = _exp_0[4] | ||
635 | if _obj_0 ~= nil then | ||
636 | _val_3 = _obj_0.b | ||
637 | end | ||
638 | end | ||
639 | local _val_4 | ||
640 | do | ||
641 | local _obj_0 = _exp_0[5] | ||
642 | if _obj_0 ~= nil then | ||
643 | _val_4 = _obj_0.a | ||
644 | end | ||
645 | end | ||
646 | local _val_5 | ||
647 | do | ||
648 | local _obj_0 = _exp_0[5] | ||
649 | if _obj_0 ~= nil then | ||
650 | _val_5 = _obj_0.b | ||
651 | end | ||
652 | end | ||
653 | if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and sixth ~= nil then | ||
654 | print("matched", sixth) | ||
655 | end | ||
656 | end | ||
657 | end | ||
658 | end | ||
659 | do | ||
660 | local v = "hello" | ||
661 | if "hello" == v then | ||
662 | print("matched hello") | ||
663 | else | ||
664 | print("not matched") | ||
665 | end | ||
666 | end | ||
667 | do | ||
668 | local f | ||
669 | f = function() | ||
670 | return "ok" | ||
671 | end | ||
672 | local val = f() | ||
673 | if "ok" == val then | ||
674 | print("it's ok") | ||
675 | end | ||
676 | end | ||
677 | do | ||
678 | local g | ||
679 | g = function() | ||
680 | return 42 | ||
681 | end | ||
682 | local result = g() | ||
683 | if 1 == result or 2 == result then | ||
684 | print("small") | ||
685 | elseif 42 == result then | ||
686 | print("life universe everything") | ||
687 | else | ||
688 | print("other " .. tostring(result)) | ||
689 | end | ||
690 | end | ||
691 | do | ||
692 | local check | ||
693 | check = function() | ||
694 | if true then | ||
695 | return "yes" | ||
696 | else | ||
697 | return "no" | ||
698 | end | ||
699 | end | ||
700 | local x = check() | ||
701 | if "yes" == x then | ||
702 | print("affirmative") | ||
703 | else | ||
704 | print("negative") | ||
705 | end | ||
706 | end | ||
707 | do | ||
708 | local t | ||
709 | t = function() | ||
710 | local tb = { | ||
711 | a = 1 | ||
712 | } | ||
713 | tb.a = 2 | ||
714 | return tb | ||
715 | end | ||
716 | local data = t() | ||
717 | local _type_0 = type(data) | ||
718 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
719 | local _match_0 = false | ||
720 | if _tab_0 then | ||
721 | if 2 == data.a then | ||
722 | _match_0 = true | ||
723 | print("matched") | ||
724 | end | ||
725 | end | ||
726 | if not _match_0 then | ||
727 | print("not matched") | ||
728 | end | ||
729 | end | ||
730 | do | ||
731 | local clientData = { | ||
732 | "Meta", | ||
733 | "CUST_1001", | ||
734 | "CHK123" | ||
735 | } | ||
736 | local _type_0 = type(clientData) | ||
737 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
738 | if _tab_0 then | ||
739 | local metadata | ||
740 | do | ||
741 | local _accum_0 = { } | ||
742 | local _len_0 = 1 | ||
743 | local _max_0 = #clientData + -3 + 1 | ||
744 | for _index_0 = 1, _max_0 do | ||
745 | local _item_0 = clientData[_index_0] | ||
746 | _accum_0[_len_0] = _item_0 | ||
747 | _len_0 = _len_0 + 1 | ||
748 | end | ||
749 | metadata = _accum_0 | ||
750 | end | ||
751 | local customerId = clientData[#clientData - 1] | ||
752 | local checksum = clientData[#clientData] | ||
753 | if customerId ~= nil and checksum ~= nil then | ||
754 | print(metadata) | ||
755 | print(customerId) | ||
756 | print(checksum) | ||
757 | end | ||
758 | end | ||
759 | end | ||
760 | do | ||
761 | local handlePath | ||
762 | handlePath = function(segments) | ||
763 | local _type_0 = type(segments) | ||
764 | local _tab_0 = "table" == _type_0 or "userdata" == _type_0 | ||
765 | if _tab_0 then | ||
766 | local resource = segments[#segments - 1] | ||
767 | local action = segments[#segments] | ||
768 | if resource ~= nil and action ~= nil then | ||
769 | print("Resource:", resource) | ||
770 | return print("Action:", action) | ||
771 | end | ||
772 | end | ||
773 | end | ||
774 | handlePath({ | ||
775 | "admin", | ||
776 | "logs", | ||
777 | "view" | ||
778 | }) | ||
779 | end | ||
418 | return nil | 780 | return nil |
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 5fd1821..040a325 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua | |||
@@ -239,9 +239,11 @@ x = 0 | |||
239 | local _list_0 = values | 239 | local _list_0 = values |
240 | for _index_0 = 1, #_list_0 do | 240 | for _index_0 = 1, #_list_0 do |
241 | local v = _list_0[_index_0] | 241 | local v = _list_0[_index_0] |
242 | if ntype(v) == "fndef" then | 242 | _ = ((function() |
243 | _ = x + 1 | 243 | if ntype(v) == "fndef" then |
244 | end | 244 | return x + 1 |
245 | end | ||
246 | end)()) | ||
245 | end | 247 | end |
246 | hello = { | 248 | hello = { |
247 | something = world, | 249 | something = world, |
diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index f358811..3f851de 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua | |||
@@ -366,6 +366,28 @@ local menus = { | |||
366 | } | 366 | } |
367 | } | 367 | } |
368 | } | 368 | } |
369 | _ = { | ||
370 | boolean = { | ||
371 | true, | ||
372 | false | ||
373 | }, | ||
374 | float = { | ||
375 | 3.14, | ||
376 | -6.8523015e+5 | ||
377 | }, | ||
378 | int = { | ||
379 | 123, | ||
380 | -685230 | ||
381 | }, | ||
382 | null = { | ||
383 | nodeName = 'node', | ||
384 | parent = nil | ||
385 | }, | ||
386 | string = { | ||
387 | 'Hello world', | ||
388 | "newline\nnewline2" | ||
389 | } | ||
390 | } | ||
369 | local tb | 391 | local tb |
370 | do | 392 | do |
371 | local _tab_0 = { } | 393 | local _tab_0 = { } |
diff --git a/spec/outputs/try_catch.lua b/spec/outputs/try_catch.lua index d4c80c1..edb2341 100644 --- a/spec/outputs/try_catch.lua +++ b/spec/outputs/try_catch.lua | |||
@@ -8,10 +8,10 @@ local _anon_func_2 = function(tb) | |||
8 | return tb.func() | 8 | return tb.func() |
9 | end | 9 | end |
10 | local _anon_func_3 = function(tb) | 10 | local _anon_func_3 = function(tb) |
11 | return tb.func() | 11 | return (tb.func()) |
12 | end | 12 | end |
13 | local _anon_func_4 = function(tb) | 13 | local _anon_func_4 = function(tb) |
14 | return tb:func(1, 2, 3) | 14 | return (tb:func(1, 2, 3)) |
15 | end | 15 | end |
16 | local _anon_func_5 = function(tb) | 16 | local _anon_func_5 = function(tb) |
17 | return tb.func(1) | 17 | return tb.func(1) |
@@ -22,6 +22,44 @@ end | |||
22 | local _anon_func_7 = function(a, b, c, tb) | 22 | local _anon_func_7 = function(a, b, c, tb) |
23 | return tb.f(a, b, c) | 23 | return tb.f(a, b, c) |
24 | end | 24 | end |
25 | local _anon_func_8 = function(_arg_0, ...) | ||
26 | local ok = _arg_0 | ||
27 | return ... | ||
28 | end | ||
29 | local _anon_func_10 = function(_arg_0, ...) | ||
30 | local _ok_0 = _arg_0 | ||
31 | if _ok_0 then | ||
32 | return ... | ||
33 | end | ||
34 | end | ||
35 | local _anon_func_9 = function(func, pcall) | ||
36 | return _anon_func_10(pcall(func)) | ||
37 | end | ||
38 | local _anon_func_12 = function(_arg_0, ...) | ||
39 | local _ok_0 = _arg_0 | ||
40 | if _ok_0 then | ||
41 | return ... | ||
42 | end | ||
43 | end | ||
44 | local _anon_func_11 = function(func, pcall) | ||
45 | return _anon_func_12(pcall(func)) | ||
46 | end | ||
47 | local _anon_func_14 = function(_arg_0, ...) | ||
48 | local _ok_0 = _arg_0 | ||
49 | if _ok_0 then | ||
50 | return ... | ||
51 | end | ||
52 | end | ||
53 | local _anon_func_15 = function(func, print) | ||
54 | print(123) | ||
55 | return func() | ||
56 | end | ||
57 | local _anon_func_13 = function(func, print, xpcall) | ||
58 | return _anon_func_14(xpcall(_anon_func_15, function(e) | ||
59 | print(e) | ||
60 | return e | ||
61 | end, func, print)) | ||
62 | end | ||
25 | local f | 63 | local f |
26 | f = function() | 64 | f = function() |
27 | xpcall(function() | 65 | xpcall(function() |
@@ -64,7 +102,7 @@ f = function() | |||
64 | print("OK") | 102 | print("OK") |
65 | end | 103 | end |
66 | if xpcall(function() | 104 | if xpcall(function() |
67 | return func(1) | 105 | return (func(1)) |
68 | end, function(err) | 106 | end, function(err) |
69 | return print(err) | 107 | return print(err) |
70 | end) then | 108 | end) then |
@@ -104,10 +142,236 @@ f = function() | |||
104 | do | 142 | do |
105 | x(function() | 143 | x(function() |
106 | local tb, a, b, c | 144 | local tb, a, b, c |
107 | f = function() | 145 | local f1 |
146 | f1 = function() | ||
108 | return pcall(_anon_func_7, a, b, c, tb) | 147 | return pcall(_anon_func_7, a, b, c, tb) |
109 | end | 148 | end |
110 | end) | 149 | end) |
111 | end | 150 | end |
151 | do | ||
152 | local f1 | ||
153 | f1 = function() | ||
154 | do | ||
155 | return _anon_func_8(pcall(function() | ||
156 | return func() | ||
157 | end)) | ||
158 | end | ||
159 | end | ||
160 | end | ||
161 | do | ||
162 | local func | ||
163 | local a, b, c | ||
164 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) | ||
165 | if _ok_0 then | ||
166 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
167 | end | ||
168 | end | ||
169 | do | ||
170 | local a, b, c | ||
171 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
172 | return func() | ||
173 | end) | ||
174 | if _ok_0 then | ||
175 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
176 | end | ||
177 | end | ||
178 | do | ||
179 | local a | ||
180 | local _exp_0 = (_anon_func_9(func, pcall)) | ||
181 | if _exp_0 ~= nil then | ||
182 | a = _exp_0 | ||
183 | else | ||
184 | a = "default" | ||
185 | end | ||
186 | end | ||
187 | do | ||
188 | f(_anon_func_11(func, pcall)) | ||
189 | end | ||
190 | do | ||
191 | f(_anon_func_13(func, print, xpcall)) | ||
192 | end | ||
112 | return nil | 193 | return nil |
113 | end | 194 | end |
195 | local _anon_func_16 = function(a, b, c, tb) | ||
196 | return tb.f(a, b, c) | ||
197 | end | ||
198 | local _anon_func_17 = function(_arg_0, ...) | ||
199 | local ok = _arg_0 | ||
200 | return ... | ||
201 | end | ||
202 | do | ||
203 | xpcall(function() | ||
204 | return func(1, 2, 3) | ||
205 | end, function(err) | ||
206 | return print(err) | ||
207 | end) | ||
208 | xpcall(function() | ||
209 | return func(1, 2, 3) | ||
210 | end, function(err) | ||
211 | return print(err) | ||
212 | end) | ||
213 | pcall(function() | ||
214 | print("trying") | ||
215 | return func(1, 2, 3) | ||
216 | end) | ||
217 | do | ||
218 | local success, result = xpcall(function() | ||
219 | return func(1, 2, 3) | ||
220 | end, function(err) | ||
221 | return print(err) | ||
222 | end) | ||
223 | success, result = pcall(function() | ||
224 | return func(1, 2, 3) | ||
225 | end) | ||
226 | end | ||
227 | local tb = { } | ||
228 | pcall(function() | ||
229 | return tb.func | ||
230 | end) | ||
231 | pcall(function() | ||
232 | return tb.func() | ||
233 | end) | ||
234 | pcall(function() | ||
235 | return tb.func() | ||
236 | end) | ||
237 | pcall(function() | ||
238 | return (tb.func()) | ||
239 | end) | ||
240 | pcall(function() | ||
241 | return (tb:func(1, 2, 3)) | ||
242 | end) | ||
243 | pcall(function() | ||
244 | return tb.func(1) | ||
245 | end) | ||
246 | pcall(function() | ||
247 | return tb.func(1) | ||
248 | end) | ||
249 | if (xpcall(function() | ||
250 | return func(1) | ||
251 | end, function(err) | ||
252 | return print(err) | ||
253 | end)) then | ||
254 | print("OK") | ||
255 | end | ||
256 | if xpcall(function() | ||
257 | return (func(1)) | ||
258 | end, function(err) | ||
259 | return print(err) | ||
260 | end) then | ||
261 | print("OK") | ||
262 | end | ||
263 | do | ||
264 | do | ||
265 | local success, result = pcall(function() | ||
266 | return func("abc", 123) | ||
267 | end) | ||
268 | if success then | ||
269 | print(result) | ||
270 | end | ||
271 | end | ||
272 | local success, result = xpcall(function() | ||
273 | return func("abc", 123) | ||
274 | end, function(err) | ||
275 | return print(err) | ||
276 | end) | ||
277 | success, result = xpcall(function() | ||
278 | return func("abc", 123) | ||
279 | end, function(err) | ||
280 | return print(err) | ||
281 | end) | ||
282 | if success then | ||
283 | print(result) | ||
284 | end | ||
285 | end | ||
286 | do | ||
287 | pcall(function() | ||
288 | return func(1, 2, 3) | ||
289 | end) | ||
290 | pcall(function() | ||
291 | return func(1, 2, 3) | ||
292 | end) | ||
293 | end | ||
294 | do | ||
295 | x(function() | ||
296 | local tb, a, b, c | ||
297 | local f1 | ||
298 | f1 = function() | ||
299 | return pcall(_anon_func_16, a, b, c, tb) | ||
300 | end | ||
301 | end) | ||
302 | end | ||
303 | do | ||
304 | local f1 | ||
305 | f1 = function() | ||
306 | do | ||
307 | return _anon_func_17(pcall(function() | ||
308 | return func() | ||
309 | end)) | ||
310 | end | ||
311 | end | ||
312 | end | ||
313 | do | ||
314 | local func | ||
315 | local a, b, c | ||
316 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func) | ||
317 | if _ok_0 then | ||
318 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
319 | end | ||
320 | end | ||
321 | do | ||
322 | local a, b, c | ||
323 | local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function() | ||
324 | return func() | ||
325 | end) | ||
326 | if _ok_0 then | ||
327 | a, b, c = _ret_0, _ret_1, _ret_2 | ||
328 | end | ||
329 | end | ||
330 | do | ||
331 | local a | ||
332 | local _exp_0 = ((function() | ||
333 | return (function(_arg_0, ...) | ||
334 | local _ok_0 = _arg_0 | ||
335 | if _ok_0 then | ||
336 | return ... | ||
337 | end | ||
338 | end)(pcall(function() | ||
339 | return func() | ||
340 | end)) | ||
341 | end)()) | ||
342 | if _exp_0 ~= nil then | ||
343 | a = _exp_0 | ||
344 | else | ||
345 | a = "default" | ||
346 | end | ||
347 | end | ||
348 | do | ||
349 | f((function() | ||
350 | return (function(_arg_0, ...) | ||
351 | local _ok_0 = _arg_0 | ||
352 | if _ok_0 then | ||
353 | return ... | ||
354 | end | ||
355 | end)(pcall(function() | ||
356 | return func() | ||
357 | end)) | ||
358 | end)()) | ||
359 | end | ||
360 | do | ||
361 | f((function() | ||
362 | return (function(_arg_0, ...) | ||
363 | local _ok_0 = _arg_0 | ||
364 | if _ok_0 then | ||
365 | return ... | ||
366 | end | ||
367 | end)(xpcall(function() | ||
368 | print(123) | ||
369 | return func() | ||
370 | end, function(e) | ||
371 | print(e) | ||
372 | return e | ||
373 | end)) | ||
374 | end)()) | ||
375 | end | ||
376 | end | ||
377 | return nil | ||
diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua index bf43953..e00d016 100644 --- a/spec/outputs/unicode/assign.lua +++ b/spec/outputs/unicode/assign.lua | |||
@@ -36,17 +36,15 @@ local _u53d8_u91cfx | |||
36 | do | 36 | do |
37 | local _u51fd_u6570 = _u83b7_u53d6_u5904_u7406_u51fd_u6570() | 37 | local _u51fd_u6570 = _u83b7_u53d6_u5904_u7406_u51fd_u6570() |
38 | if _u51fd_u6570 then | 38 | if _u51fd_u6570 then |
39 | do | 39 | _u53d8_u91cfx = ((function() |
40 | _u51fd_u6570() | 40 | _u51fd_u6570() |
41 | _u53d8_u91cfx = 123 | 41 | return 123 |
42 | end | 42 | end)()) |
43 | end | 43 | end |
44 | end | 44 | end |
45 | local _anon_func_0 = function(_u6253_u5370) | 45 | local _anon_func_0 = function(_u6253_u5370) |
46 | do | 46 | _u6253_u5370(123) |
47 | _u6253_u5370(123) | 47 | return { } |
48 | return { } | ||
49 | end | ||
50 | end | 48 | end |
51 | return __u65e0_u6548_u53d8_u91cf(function() | 49 | return __u65e0_u6548_u53d8_u91cf(function() |
52 | setmetatable(a_u53d8_u91cf, _anon_func_0(_u6253_u5370)) | 50 | setmetatable(a_u53d8_u91cf, _anon_func_0(_u6253_u5370)) |
diff --git a/spec/outputs/unicode/attrib.lua b/spec/outputs/unicode/attrib.lua index 1c48de4..5e5bb99 100644 --- a/spec/outputs/unicode/attrib.lua +++ b/spec/outputs/unicode/attrib.lua | |||
@@ -48,17 +48,21 @@ do | |||
48 | end | 48 | end |
49 | local _u5173_u95ed_u53d8_u91cfb | 49 | local _u5173_u95ed_u53d8_u91cfb |
50 | if not false then | 50 | if not false then |
51 | if _u6761_u4ef6x then | 51 | _u5173_u95ed_u53d8_u91cfb = ((function() |
52 | _u5173_u95ed_u53d8_u91cfb = 1 | 52 | if _u6761_u4ef6x then |
53 | end | 53 | return 1 |
54 | end | ||
55 | end)()) | ||
54 | end | 56 | end |
55 | local _close_0 <close> = _u5173_u95ed_u53d8_u91cfb | 57 | local _close_0 <close> = _u5173_u95ed_u53d8_u91cfb |
56 | local _u5e38_u91cfc | 58 | local _u5e38_u91cfc |
57 | if true then | 59 | if true then |
58 | local _exp_0 = _u6761_u4ef6x | 60 | _u5e38_u91cfc = ((function() |
59 | if "abc" == _exp_0 then | 61 | local _exp_0 = _u6761_u4ef6x |
60 | _u5e38_u91cfc = 998 | 62 | if "abc" == _exp_0 then |
61 | end | 63 | return 998 |
64 | end | ||
65 | end)()) | ||
62 | end | 66 | end |
63 | local _u5173_u95ed_u53d8_u91cfd | 67 | local _u5173_u95ed_u53d8_u91cfd |
64 | if (function() | 68 | if (function() |
diff --git a/spec/outputs/unicode/comprehension.lua b/spec/outputs/unicode/comprehension.lua index 60e490f..92bce69 100644 --- a/spec/outputs/unicode/comprehension.lua +++ b/spec/outputs/unicode/comprehension.lua | |||
@@ -243,8 +243,11 @@ end | |||
243 | do | 243 | do |
244 | local _accum_0 = { } | 244 | local _accum_0 = { } |
245 | local _len_0 = 1 | 245 | local _len_0 = 1 |
246 | local _min_0 = 1 + 2 | ||
246 | local _max_0 = 3 + 4 | 247 | local _max_0 = 3 + 4 |
247 | for _index_0 = 1 + 2, _max_0 < 0 and #_u5217_u8868 + _max_0 or _max_0 do | 248 | _min_0 = _min_0 < 0 and #_u5217_u8868 + _min_0 + 1 or _min_0 |
249 | _max_0 = _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0 | ||
250 | for _index_0 = _min_0, _max_0 do | ||
248 | local _u9879_u76ee = _u5217_u8868[_index_0] | 251 | local _u9879_u76ee = _u5217_u8868[_index_0] |
249 | _accum_0[_len_0] = _u9879_u76ee | 252 | _accum_0[_len_0] = _u9879_u76ee |
250 | _len_0 = _len_0 + 1 | 253 | _len_0 = _len_0 + 1 |
@@ -254,8 +257,11 @@ end | |||
254 | do | 257 | do |
255 | local _accum_0 = { } | 258 | local _accum_0 = { } |
256 | local _len_0 = 1 | 259 | local _len_0 = 1 |
260 | local _min_0 = _u4f60_u597d() * 4 | ||
257 | local _max_0 = 2 - _u4e1c_u897f[4] | 261 | local _max_0 = 2 - _u4e1c_u897f[4] |
258 | for _index_0 = _u4f60_u597d() * 4, _max_0 < 0 and #_u5217_u8868 + _max_0 or _max_0 do | 262 | _min_0 = _min_0 < 0 and #_u5217_u8868 + _min_0 + 1 or _min_0 |
263 | _max_0 = _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0 | ||
264 | for _index_0 = _min_0, _max_0 do | ||
259 | local _u9879_u76ee = _u5217_u8868[_index_0] | 265 | local _u9879_u76ee = _u5217_u8868[_index_0] |
260 | _accum_0[_len_0] = _u9879_u76ee | 266 | _accum_0[_len_0] = _u9879_u76ee |
261 | _len_0 = _len_0 + 1 | 267 | _len_0 = _len_0 + 1 |
diff --git a/spec/outputs/unicode/do.lua b/spec/outputs/unicode/do.lua index f9c3079..7bf1da3 100644 --- a/spec/outputs/unicode/do.lua +++ b/spec/outputs/unicode/do.lua | |||
@@ -32,10 +32,10 @@ local _u53d8_u91cft = { | |||
32 | } | 32 | } |
33 | return function(_u53c2_u6570y, _u53c2_u6570k) | 33 | return function(_u53c2_u6570y, _u53c2_u6570k) |
34 | if _u53c2_u6570y == nil then | 34 | if _u53c2_u6570y == nil then |
35 | do | 35 | _u53c2_u6570y = ((function() |
36 | _u53d8_u91cfx = 10 + 2 | 36 | _u53d8_u91cfx = 10 + 2 |
37 | _u53c2_u6570y = _u53d8_u91cfx | 37 | return _u53d8_u91cfx |
38 | end | 38 | end)()) |
39 | end | 39 | end |
40 | if _u53c2_u6570k == nil then | 40 | if _u53c2_u6570k == nil then |
41 | do | 41 | do |
diff --git a/spec/outputs/unicode/lists.lua b/spec/outputs/unicode/lists.lua index aafd516..3bf6f50 100644 --- a/spec/outputs/unicode/lists.lua +++ b/spec/outputs/unicode/lists.lua | |||
@@ -229,31 +229,36 @@ _u53d8_u91cfx = { | |||
229 | 6, | 229 | 6, |
230 | 7 | 230 | 7 |
231 | } | 231 | } |
232 | local _max_0 = -5 | 232 | local _max_0 = #_u53d8_u91cfx + -5 + 1 |
233 | for _index_0 = 2, _max_0 < 0 and #_u53d8_u91cfx + _max_0 or _max_0, 2 do | 233 | for _index_0 = 2, _max_0, 2 do |
234 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 234 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
235 | _u6253_u5370(_u53d8_u91cfy) | 235 | _u6253_u5370(_u53d8_u91cfy) |
236 | end | 236 | end |
237 | local _max_1 = 3 | 237 | for _index_0 = 1, 3 do |
238 | for _index_0 = 1, _max_1 < 0 and #_u53d8_u91cfx + _max_1 or _max_1 do | ||
239 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 238 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
240 | _u6253_u5370(_u53d8_u91cfy) | 239 | _u6253_u5370(_u53d8_u91cfy) |
241 | end | 240 | end |
242 | for _index_0 = 2, #_u53d8_u91cfx do | 241 | local _max_1 = #_u53d8_u91cfx |
242 | for _index_0 = 2, _max_1 do | ||
243 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 243 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
244 | _u6253_u5370(_u53d8_u91cfy) | 244 | _u6253_u5370(_u53d8_u91cfy) |
245 | end | 245 | end |
246 | for _index_0 = 1, #_u53d8_u91cfx, 2 do | 246 | local _max_2 = #_u53d8_u91cfx |
247 | for _index_0 = 1, _max_2, 2 do | ||
247 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 248 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
248 | _u6253_u5370(_u53d8_u91cfy) | 249 | _u6253_u5370(_u53d8_u91cfy) |
249 | end | 250 | end |
250 | for _index_0 = 2, #_u53d8_u91cfx, 2 do | 251 | local _max_3 = #_u53d8_u91cfx |
252 | for _index_0 = 2, _max_3, 2 do | ||
251 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 253 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
252 | _u6253_u5370(_u53d8_u91cfy) | 254 | _u6253_u5370(_u53d8_u91cfy) |
253 | end | 255 | end |
254 | local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 | 256 | local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 |
255 | local _max_2 = _u53d8_u91cfb | 257 | local _min_0 = _u53d8_u91cfa |
256 | for _index_0 = _u53d8_u91cfa, _max_2 < 0 and #_u53d8_u91cfx + _max_2 or _max_2, _u53d8_u91cfc do | 258 | local _max_4 = _u53d8_u91cfb |
259 | _min_0 = _min_0 < 0 and #_u53d8_u91cfx + _min_0 + 1 or _min_0 | ||
260 | _max_4 = _max_4 < 0 and #_u53d8_u91cfx + _max_4 + 1 or _max_4 | ||
261 | for _index_0 = _min_0, _max_4, _u53d8_u91cfc do | ||
257 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] | 262 | local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] |
258 | _u6253_u5370(_u53d8_u91cfy) | 263 | _u6253_u5370(_u53d8_u91cfy) |
259 | end | 264 | end |
diff --git a/spec/outputs/unicode/loops.lua b/spec/outputs/unicode/loops.lua index 8379993..27bbe2e 100644 --- a/spec/outputs/unicode/loops.lua +++ b/spec/outputs/unicode/loops.lua | |||
@@ -60,8 +60,8 @@ do | |||
60 | local _u53d8_u91cfy = _u4f60_u597d[_index_0] | 60 | local _u53d8_u91cfy = _u4f60_u597d[_index_0] |
61 | if _u53d8_u91cfy % 2 == 0 then | 61 | if _u53d8_u91cfy % 2 == 0 then |
62 | _accum_0[_len_0] = _u53d8_u91cfy | 62 | _accum_0[_len_0] = _u53d8_u91cfy |
63 | _len_0 = _len_0 + 1 | ||
63 | end | 64 | end |
64 | _len_0 = _len_0 + 1 | ||
65 | end | 65 | end |
66 | _u53d8_u91cfx = _accum_0 | 66 | _u53d8_u91cfx = _accum_0 |
67 | end | 67 | end |
@@ -132,13 +132,11 @@ do | |||
132 | end | 132 | end |
133 | do | 133 | do |
134 | local _accum_0 = { } | 134 | local _accum_0 = { } |
135 | local _len_0 = 1 | ||
136 | local _list_2 = 3 | 135 | local _list_2 = 3 |
137 | for _index_0 = 1, #_list_2 do | 136 | for _index_0 = 1, #_list_2 do |
138 | local _u4e1c_u897f = _list_2[_index_0] | 137 | local _u4e1c_u897f = _list_2[_index_0] |
139 | _u53d8_u91cfy = "ä½ å¥½" | 138 | _u53d8_u91cfy = "ä½ å¥½" |
140 | break | 139 | break |
141 | _len_0 = _len_0 + 1 | ||
142 | end | 140 | end |
143 | _u53d8_u91cfx = _accum_0 | 141 | _u53d8_u91cfx = _accum_0 |
144 | end | 142 | end |
diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua index 099080f..b4e78cd 100644 --- a/spec/outputs/unicode/macro.lua +++ b/spec/outputs/unicode/macro.lua | |||
@@ -215,24 +215,8 @@ do | |||
215 | -- 这有个注释 | 215 | -- 这有个注释 |
216 | end | 216 | end |
217 | local _ = require('下划线') | 217 | local _ = require('下划线') |
218 | local _call_0 = (_({ | 218 | local _anon_func_0 = function(_) |
219 | 1, | 219 | local _call_0 = (_({ |
220 | 2, | ||
221 | 3, | ||
222 | 4, | ||
223 | -2, | ||
224 | 3 | ||
225 | })) | ||
226 | _call_0 = _call_0["链"](_call_0) | ||
227 | _call_0 = _call_0["æ˜ å°„"](_call_0, function(self) | ||
228 | return self * 2 | ||
229 | end) | ||
230 | _call_0 = _call_0["过滤"](_call_0, function(self) | ||
231 | return self > 3 | ||
232 | end) | ||
233 | local _u7ed3_u679ca = _call_0["å–值"](_call_0) | ||
234 | do | ||
235 | local _call_1 = (_({ | ||
236 | 1, | 220 | 1, |
237 | 2, | 221 | 2, |
238 | 3, | 222 | 3, |
@@ -240,27 +224,70 @@ do | |||
240 | -2, | 224 | -2, |
241 | 3 | 225 | 3 |
242 | })) | 226 | })) |
243 | _call_1 = _call_1["链"](_call_1) | 227 | return _call_0["链"](_call_0) |
244 | _call_1 = _call_1["æ˜ å°„"](_call_1, function(self) | 228 | end |
245 | return self * 2 | 229 | local _call_0 = ((function() |
246 | end) | 230 | local _call_0 = ((function() |
247 | _call_1 = _call_1["过滤"](_call_1, function(self) | 231 | local _call_0 = (_anon_func_0(_)) |
232 | return _call_0["æ˜ å°„"](_call_0, function(self) | ||
233 | return self * 2 | ||
234 | end) | ||
235 | end)()) | ||
236 | return _call_0["过滤"](_call_0, function(self) | ||
248 | return self > 3 | 237 | return self > 3 |
249 | end) | 238 | end) |
239 | end)()) | ||
240 | local _u7ed3_u679ca = _call_0["å–值"](_call_0) | ||
241 | local _anon_func_1 = function(_) | ||
242 | local _call_1 = (_({ | ||
243 | 1, | ||
244 | 2, | ||
245 | 3, | ||
246 | 4, | ||
247 | -2, | ||
248 | 3 | ||
249 | })) | ||
250 | return _call_1["链"](_call_1) | ||
251 | end | ||
252 | do | ||
253 | local _call_1 = ((function() | ||
254 | local _call_1 = ((function() | ||
255 | local _call_1 = (_anon_func_1(_)) | ||
256 | return _call_1["æ˜ å°„"](_call_1, function(self) | ||
257 | return self * 2 | ||
258 | end) | ||
259 | end)()) | ||
260 | return _call_1["过滤"](_call_1, function(self) | ||
261 | return self > 3 | ||
262 | end) | ||
263 | end)()) | ||
250 | _call_1["æ¯ä¸€ä¸ª"](_call_1, function(self) | 264 | _call_1["æ¯ä¸€ä¸ª"](_call_1, function(self) |
251 | return _u6253_u5370(self) | 265 | return _u6253_u5370(self) |
252 | end) | 266 | end) |
253 | end | 267 | end |
254 | local _call_1 = _u539f_u70b9["å˜æ¢"]["æ ¹èŠ‚ç‚¹"]["游æˆå¯¹è±¡"] | 268 | local _anon_func_2 = function(_u539f_u70b9) |
255 | _call_1 = _call_1["父节点"](_call_1) | 269 | local _call_1 = _u539f_u70b9["å˜æ¢"]["æ ¹èŠ‚ç‚¹"]["游æˆå¯¹è±¡"] |
256 | _call_1 = _call_1["åŽä»£"](_call_1) | 270 | return _call_1["父节点"](_call_1) |
257 | _call_1 = _call_1["选择å¯ç”¨"](_call_1) | 271 | end |
258 | _call_1 = _call_1["选择å¯è§"](_call_1) | 272 | local _call_1 = ((function() |
259 | _call_1 = _call_1["æ ‡ç¾ç‰äºŽ"](_call_1, "fx") | 273 | local _call_1 = ((function() |
260 | _call_1 = _call_1["å…¶ä¸"](_call_1, function(x) | 274 | local _call_1 = ((function() |
261 | local _call_2 = x["åç§°"] | 275 | local _call_1 = ((function() |
262 | return _call_2["结尾为"](_call_2, "(克隆)") | 276 | local _call_1 = ((function() |
263 | end) | 277 | local _call_1 = (_anon_func_2(_u539f_u70b9)) |
278 | return _call_1["åŽä»£"](_call_1) | ||
279 | end)()) | ||
280 | return _call_1["选择å¯ç”¨"](_call_1) | ||
281 | end)()) | ||
282 | return _call_1["选择å¯è§"](_call_1) | ||
283 | end)()) | ||
284 | return _call_1["æ ‡ç¾ç‰äºŽ"](_call_1, "fx") | ||
285 | end)()) | ||
286 | return _call_1["å…¶ä¸"](_call_1, function(x) | ||
287 | local _call_2 = x["åç§°"] | ||
288 | return _call_2["结尾为"](_call_2, "(克隆)") | ||
289 | end) | ||
290 | end)()) | ||
264 | _u7ed3_u679c = _call_1["æ‘§æ¯"](_call_1) | 291 | _u7ed3_u679c = _call_1["æ‘§æ¯"](_call_1) |
265 | do | 292 | do |
266 | do | 293 | do |
@@ -332,10 +359,8 @@ local _1 | |||
332 | _1 = function() | 359 | _1 = function() |
333 | _u6253_u5370(1) | 360 | _u6253_u5370(1) |
334 | local _accum_0 = { } | 361 | local _accum_0 = { } |
335 | local _len_0 = 1 | ||
336 | while false do | 362 | while false do |
337 | break | 363 | break |
338 | _len_0 = _len_0 + 1 | ||
339 | end | 364 | end |
340 | return _accum_0 | 365 | return _accum_0 |
341 | end | 366 | end |
diff --git a/spec/outputs/unicode/multiline_chain.lua b/spec/outputs/unicode/multiline_chain.lua index c1da13f..61e7057 100644 --- a/spec/outputs/unicode/multiline_chain.lua +++ b/spec/outputs/unicode/multiline_chain.lua | |||
@@ -59,10 +59,8 @@ _u51fd_u6570 = function() | |||
59 | return _accum_0 | 59 | return _accum_0 |
60 | end | 60 | end |
61 | local _anon_func_0 = function(_u53d8_u91cfa) | 61 | local _anon_func_0 = function(_u53d8_u91cfa) |
62 | do | 62 | local _call_1 = _u53d8_u91cfa |
63 | local _call_1 = _u53d8_u91cfa | 63 | return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc") |
64 | return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc") | ||
65 | end | ||
66 | end | 64 | end |
67 | local _u51fd_u65701 | 65 | local _u51fd_u65701 |
68 | _u51fd_u65701 = function() | 66 | _u51fd_u65701 = function() |
diff --git a/spec/outputs/unicode/syntax.lua b/spec/outputs/unicode/syntax.lua index ea97bb9..a13302b 100644 --- a/spec/outputs/unicode/syntax.lua +++ b/spec/outputs/unicode/syntax.lua | |||
@@ -258,9 +258,11 @@ _u53d8_u91cfx = 0 | |||
258 | local _list_0 = _u503c | 258 | local _list_0 = _u503c |
259 | for _index_0 = 1, #_list_0 do | 259 | for _index_0 = 1, #_list_0 do |
260 | local _u53d8_u91cfv = _list_0[_index_0] | 260 | local _u53d8_u91cfv = _list_0[_index_0] |
261 | if ntype(_u53d8_u91cfv) == "函数定义" then | 261 | _ = ((function() |
262 | _ = _u53d8_u91cfx + 1 | 262 | if ntype(_u53d8_u91cfv) == "函数定义" then |
263 | end | 263 | return _u53d8_u91cfx + 1 |
264 | end | ||
265 | end)()) | ||
264 | end | 266 | end |
265 | _u4f60_u597d = { | 267 | _u4f60_u597d = { |
266 | ["æŸç‰©"] = _u4e16_u754c, | 268 | ["æŸç‰©"] = _u4e16_u754c, |
@@ -284,10 +286,8 @@ _ = 5 - _u4ec0_u4e48(_u65e0_u804a) | |||
284 | _u4ec0_u4e48(_u65e0_u804a - 5) | 286 | _u4ec0_u4e48(_u65e0_u804a - 5) |
285 | _u53d8_u91cfx = _u4f60_u597d - _u4e16_u754c - _u67d0_u7269 | 287 | _u53d8_u91cfx = _u4f60_u597d - _u4e16_u754c - _u67d0_u7269 |
286 | local _anon_func_0 = function(_u4ec0_u4e48) | 288 | local _anon_func_0 = function(_u4ec0_u4e48) |
287 | do | 289 | local _call_8 = _u4ec0_u4e48 |
288 | local _call_8 = _u4ec0_u4e48 | 290 | return _call_8["é…·"](_call_8, 100) |
289 | return _call_8["é…·"](_call_8, 100) | ||
290 | end | ||
291 | end | 291 | end |
292 | (function(_u67d0_u7269) | 292 | (function(_u67d0_u7269) |
293 | if _u67d0_u7269 == nil then | 293 | if _u67d0_u7269 == nil then |
diff --git a/spec/outputs/unicode/try_catch.lua b/spec/outputs/unicode/try_catch.lua index 22f29f9..f8c7849 100644 --- a/spec/outputs/unicode/try_catch.lua +++ b/spec/outputs/unicode/try_catch.lua | |||
@@ -32,11 +32,13 @@ pcall(function() | |||
32 | return _u8868["函数"]() | 32 | return _u8868["函数"]() |
33 | end) | 33 | end) |
34 | pcall(function() | 34 | pcall(function() |
35 | return _u8868["函数"]() | 35 | return (_u8868["函数"]()) |
36 | end) | 36 | end) |
37 | pcall(function() | 37 | pcall(function() |
38 | local _call_0 = _u8868 | 38 | return ((function() |
39 | return _call_0["函数"](_call_0, 1, 2, 3) | 39 | local _call_0 = _u8868 |
40 | return _call_0["函数"](_call_0, 1, 2, 3) | ||
41 | end)()) | ||
40 | end) | 42 | end) |
41 | pcall(function() | 43 | pcall(function() |
42 | return _u8868["函数"](1) | 44 | return _u8868["函数"](1) |
@@ -52,7 +54,7 @@ end)) then | |||
52 | _u6253_u5370("好的") | 54 | _u6253_u5370("好的") |
53 | end | 55 | end |
54 | if xpcall(function() | 56 | if xpcall(function() |
55 | return _u51fd_u6570(1) | 57 | return (_u51fd_u6570(1)) |
56 | end, function(_u9519_u8bef) | 58 | end, function(_u9519_u8bef) |
57 | return _u6253_u5370(_u9519_u8bef) | 59 | return _u6253_u5370(_u9519_u8bef) |
58 | end) then | 60 | end) then |
diff --git a/spec/outputs/unicode/vararg.lua b/spec/outputs/unicode/vararg.lua index b837006..fc894ff 100644 --- a/spec/outputs/unicode/vararg.lua +++ b/spec/outputs/unicode/vararg.lua | |||
@@ -125,14 +125,10 @@ local _anon_func_11 = function(_u9879_u76ee, ...) | |||
125 | return _tbl_0 | 125 | return _tbl_0 |
126 | end | 126 | end |
127 | local _anon_func_12 = function(_u51fd_u6570) | 127 | local _anon_func_12 = function(_u51fd_u6570) |
128 | do | 128 | return _u51fd_u6570() |
129 | return _u51fd_u6570() | ||
130 | end | ||
131 | end | 129 | end |
132 | local _anon_func_13 = function(_u51fd_u6570, ...) | 130 | local _anon_func_13 = function(_u51fd_u6570, ...) |
133 | do | 131 | return _u51fd_u6570(...) |
134 | return _u51fd_u6570(...) | ||
135 | end | ||
136 | end | 132 | end |
137 | local _anon_func_14 = function(_u51fd_u6570) | 133 | local _anon_func_14 = function(_u51fd_u6570) |
138 | local _accum_0 = { } | 134 | local _accum_0 = { } |
@@ -195,15 +191,11 @@ local _anon_func_23 = function(_u51fd_u6570, ...) | |||
195 | return nil | 191 | return nil |
196 | end | 192 | end |
197 | local _anon_func_24 = function(_u6253_u5370, select, ...) | 193 | local _anon_func_24 = function(_u6253_u5370, select, ...) |
198 | do | 194 | _u6253_u5370(select("#", ...)) |
199 | _u6253_u5370(select("#", ...)) | 195 | return _u6253_u5370(...) |
200 | return _u6253_u5370(...) | ||
201 | end | ||
202 | end | 196 | end |
203 | local _anon_func_25 = function(_u6253_u5370, ...) | 197 | local _anon_func_25 = function(_u6253_u5370, ...) |
204 | do | 198 | return _u6253_u5370(...) |
205 | return _u6253_u5370(...) | ||
206 | end | ||
207 | end | 199 | end |
208 | local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) | 200 | local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) |
209 | if 1 == _u53d8_u91cfx then | 201 | if 1 == _u53d8_u91cfx then |
@@ -214,9 +206,7 @@ local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) | |||
214 | end | 206 | end |
215 | end | 207 | end |
216 | local _anon_func_27 = function(_u6253_u5370, ...) | 208 | local _anon_func_27 = function(_u6253_u5370, ...) |
217 | do | 209 | return _u6253_u5370(...) |
218 | return _u6253_u5370(...) | ||
219 | end | ||
220 | end | 210 | end |
221 | local _anon_func_28 = function(_u6761_u4ef6) | 211 | local _anon_func_28 = function(_u6761_u4ef6) |
222 | if _u6761_u4ef6 then | 212 | if _u6761_u4ef6 then |
@@ -224,10 +214,8 @@ local _anon_func_28 = function(_u6761_u4ef6) | |||
224 | end | 214 | end |
225 | end | 215 | end |
226 | local _anon_func_29 = function(_u6253_u5370, _arg_0, ...) | 216 | local _anon_func_29 = function(_u6253_u5370, _arg_0, ...) |
227 | do | 217 | local _u8868 = _arg_0 |
228 | local _u8868 = _arg_0 | 218 | return _u6253_u5370(...) |
229 | return _u6253_u5370(...) | ||
230 | end | ||
231 | end | 219 | end |
232 | local _u8fde_u63a5 | 220 | local _u8fde_u63a5 |
233 | _u8fde_u63a5 = function(...) | 221 | _u8fde_u63a5 = function(...) |
diff --git a/spec/outputs/upvalue_func.lua b/spec/outputs/upvalue_func.lua index 3181adf..3e088be 100644 --- a/spec/outputs/upvalue_func.lua +++ b/spec/outputs/upvalue_func.lua | |||
@@ -214,10 +214,8 @@ local _anon_func_1 = function(valueB) | |||
214 | end | 214 | end |
215 | end | 215 | end |
216 | local _anon_func_2 = function(print, select, _arg_0, ...) | 216 | local _anon_func_2 = function(print, select, _arg_0, ...) |
217 | do | 217 | local ok = _arg_0 |
218 | local ok = _arg_0 | 218 | return print(select(3, ...)) |
219 | return print(select(3, ...)) | ||
220 | end | ||
221 | end | 219 | end |
222 | local _anon_func_3 = function(tb) | 220 | local _anon_func_3 = function(tb) |
223 | if tb ~= nil then | 221 | if tb ~= nil then |
@@ -242,11 +240,9 @@ local _anon_func_5 = function(getmetatable, tb) | |||
242 | return _obj_0[1 + 1](_obj_0, "abc") | 240 | return _obj_0[1 + 1](_obj_0, "abc") |
243 | end | 241 | end |
244 | local _anon_func_6 = function(tb) | 242 | local _anon_func_6 = function(tb) |
245 | do | 243 | local _call_0 = tb |
246 | local _call_0 = tb | 244 | local _call_1 = _call_0["end"](_call_0) |
247 | local _call_1 = _call_0["end"](_call_0) | 245 | return _call_1["🤣"](_call_1, 123) |
248 | return _call_1["🤣"](_call_1, 123) | ||
249 | end | ||
250 | end | 246 | end |
251 | local _anon_func_7 = function(itemA, listA) | 247 | local _anon_func_7 = function(itemA, listA) |
252 | for _index_0 = 1, #listA do | 248 | for _index_0 = 1, #listA do |
@@ -354,17 +350,13 @@ local _anon_func_16 = function(pairs, tb, tostring) | |||
354 | return _tbl_0 | 350 | return _tbl_0 |
355 | end | 351 | end |
356 | local _anon_func_17 = function(print) | 352 | local _anon_func_17 = function(print) |
357 | do | 353 | print(123) |
358 | print(123) | 354 | return "abc" |
359 | return "abc" | ||
360 | end | ||
361 | end | 355 | end |
362 | local _anon_func_18 = function(print, select, _arg_0, ...) | 356 | local _anon_func_18 = function(print, select, _arg_0, ...) |
363 | do | 357 | local success = _arg_0 |
364 | local success = _arg_0 | 358 | if success then |
365 | if success then | 359 | return print(select('#', ...)) |
366 | return print(select('#', ...)) | ||
367 | end | ||
368 | end | 360 | end |
369 | end | 361 | end |
370 | local _anon_func_19 = function(cond, i) | 362 | local _anon_func_19 = function(cond, i) |
@@ -459,11 +451,9 @@ local _anon_func_25 = function(itemA, listA) | |||
459 | return false | 451 | return false |
460 | end | 452 | end |
461 | local _anon_func_24 = function(itemA, listA, tb) | 453 | local _anon_func_24 = function(itemA, listA, tb) |
462 | do | 454 | local _call_0 = tb |
463 | local _call_0 = tb | 455 | local _call_1 = _call_0["end"](_call_0) |
464 | local _call_1 = _call_0["end"](_call_0) | 456 | return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA))) |
465 | return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA))) | ||
466 | end | ||
467 | end | 457 | end |
468 | GameEngine:onEvent("SomeEvent", function() | 458 | GameEngine:onEvent("SomeEvent", function() |
469 | return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb)) | 459 | return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb)) |
@@ -503,13 +493,11 @@ local _anon_func_27 = function(char) | |||
503 | return nil | 493 | return nil |
504 | end | 494 | end |
505 | local _anon_func_28 = function(os, _arg_0, ...) | 495 | local _anon_func_28 = function(os, _arg_0, ...) |
506 | do | 496 | local ok = _arg_0 |
507 | local ok = _arg_0 | 497 | if ok then |
508 | if ok then | 498 | return ... |
509 | return ... | 499 | else |
510 | else | 500 | return os.exit(1) |
511 | return os.exit(1) | ||
512 | end | ||
513 | end | 501 | end |
514 | end | 502 | end |
515 | local _anon_func_29 = function(debug_env_after, debug_env_before, env, func) | 503 | local _anon_func_29 = function(debug_env_after, debug_env_before, env, func) |
diff --git a/spec/outputs/vararg.lua b/spec/outputs/vararg.lua index dabba44..254aa6a 100644 --- a/spec/outputs/vararg.lua +++ b/spec/outputs/vararg.lua | |||
@@ -125,14 +125,10 @@ local _anon_func_11 = function(items, ...) | |||
125 | return _tbl_0 | 125 | return _tbl_0 |
126 | end | 126 | end |
127 | local _anon_func_12 = function(func) | 127 | local _anon_func_12 = function(func) |
128 | do | 128 | return func() |
129 | return func() | ||
130 | end | ||
131 | end | 129 | end |
132 | local _anon_func_13 = function(func, ...) | 130 | local _anon_func_13 = function(func, ...) |
133 | do | 131 | return func(...) |
134 | return func(...) | ||
135 | end | ||
136 | end | 132 | end |
137 | local _anon_func_14 = function(func) | 133 | local _anon_func_14 = function(func) |
138 | local _accum_0 = { } | 134 | local _accum_0 = { } |
@@ -195,15 +191,11 @@ local _anon_func_23 = function(func, ...) | |||
195 | return nil | 191 | return nil |
196 | end | 192 | end |
197 | local _anon_func_24 = function(print, select, ...) | 193 | local _anon_func_24 = function(print, select, ...) |
198 | do | 194 | print(select("#", ...)) |
199 | print(select("#", ...)) | 195 | return print(...) |
200 | return print(...) | ||
201 | end | ||
202 | end | 196 | end |
203 | local _anon_func_25 = function(print, ...) | 197 | local _anon_func_25 = function(print, ...) |
204 | do | 198 | return print(...) |
205 | return print(...) | ||
206 | end | ||
207 | end | 199 | end |
208 | local _anon_func_26 = function(tb, tb2, x) | 200 | local _anon_func_26 = function(tb, tb2, x) |
209 | if 1 == x then | 201 | if 1 == x then |
@@ -214,9 +206,7 @@ local _anon_func_26 = function(tb, tb2, x) | |||
214 | end | 206 | end |
215 | end | 207 | end |
216 | local _anon_func_27 = function(print, ...) | 208 | local _anon_func_27 = function(print, ...) |
217 | do | 209 | return print(...) |
218 | return print(...) | ||
219 | end | ||
220 | end | 210 | end |
221 | local _anon_func_28 = function(cond) | 211 | local _anon_func_28 = function(cond) |
222 | if cond then | 212 | if cond then |
@@ -224,10 +214,8 @@ local _anon_func_28 = function(cond) | |||
224 | end | 214 | end |
225 | end | 215 | end |
226 | local _anon_func_29 = function(print, _arg_0, ...) | 216 | local _anon_func_29 = function(print, _arg_0, ...) |
227 | do | 217 | local tb = _arg_0 |
228 | local tb = _arg_0 | 218 | return print(...) |
229 | return print(...) | ||
230 | end | ||
231 | end | 219 | end |
232 | local join | 220 | local join |
233 | join = function(...) | 221 | join = function(...) |
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 1a795c1..530915e 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua | |||
@@ -187,4 +187,66 @@ do | |||
187 | return _with_0[123] | 187 | return _with_0[123] |
188 | end | 188 | end |
189 | end | 189 | end |
190 | do | ||
191 | f((function() | ||
192 | local _with_0 = item | ||
193 | do | ||
194 | local _accum_0 | ||
195 | repeat | ||
196 | if _with_0.id > 0 then | ||
197 | _accum_0 = _with_0.content | ||
198 | break | ||
199 | end | ||
200 | until true | ||
201 | _with_0 = _accum_0 | ||
202 | end | ||
203 | return _with_0 | ||
204 | end)()) | ||
205 | local a | ||
206 | do | ||
207 | local _with_0 = tb | ||
208 | do | ||
209 | local _accum_0 | ||
210 | repeat | ||
211 | if _with_0.v then | ||
212 | _accum_0 = _with_0.a | ||
213 | break | ||
214 | end | ||
215 | until true | ||
216 | _with_0 = _accum_0 | ||
217 | end | ||
218 | a = _with_0 | ||
219 | end | ||
220 | local _accum_0 | ||
221 | while true do | ||
222 | local _with_0 = tb | ||
223 | local _accum_1 | ||
224 | repeat | ||
225 | if _with_0 ~= nil then | ||
226 | _accum_1 = 1 | ||
227 | break | ||
228 | end | ||
229 | until true | ||
230 | _with_0 = _accum_1 | ||
231 | _accum_0 = _with_0 | ||
232 | break | ||
233 | end | ||
234 | a = _accum_0 | ||
235 | end | ||
236 | do | ||
237 | local a | ||
238 | local _accum_0 | ||
239 | for i = 1, 100 do | ||
240 | local x = tb[i] | ||
241 | if x ~= nil then | ||
242 | local _des_0 = 1 | ||
243 | if _des_0 then | ||
244 | x.id = _des_0 | ||
245 | _accum_0 = x | ||
246 | break | ||
247 | end | ||
248 | end | ||
249 | end | ||
250 | a = _accum_0 | ||
251 | end | ||
190 | return nil | 252 | return nil |
diff --git a/src/3rdParty/efsw/Atomic.hpp b/src/3rdParty/efsw/Atomic.hpp index 4008dfc..9015c60 100755..100644 --- a/src/3rdParty/efsw/Atomic.hpp +++ b/src/3rdParty/efsw/Atomic.hpp | |||
@@ -3,9 +3,7 @@ | |||
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | 5 | ||
6 | #ifdef EFSW_USE_CXX11 | ||
7 | #include <atomic> | 6 | #include <atomic> |
8 | #endif | ||
9 | 7 | ||
10 | namespace efsw { | 8 | namespace efsw { |
11 | 9 | ||
@@ -14,36 +12,20 @@ template <typename T> class Atomic { | |||
14 | explicit Atomic( T set = false ) : set_( set ) {} | 12 | explicit Atomic( T set = false ) : set_( set ) {} |
15 | 13 | ||
16 | Atomic& operator=( T set ) { | 14 | Atomic& operator=( T set ) { |
17 | #ifdef EFSW_USE_CXX11 | ||
18 | set_.store( set, std::memory_order_release ); | 15 | set_.store( set, std::memory_order_release ); |
19 | #else | ||
20 | set_ = set; | ||
21 | #endif | ||
22 | return *this; | 16 | return *this; |
23 | } | 17 | } |
24 | 18 | ||
25 | explicit operator T() const { | 19 | explicit operator T() const { |
26 | #ifdef EFSW_USE_CXX11 | ||
27 | return set_.load( std::memory_order_acquire ); | 20 | return set_.load( std::memory_order_acquire ); |
28 | #else | ||
29 | return set_; | ||
30 | #endif | ||
31 | } | 21 | } |
32 | 22 | ||
33 | T load() const { | 23 | T load() const { |
34 | #ifdef EFSW_USE_CXX11 | ||
35 | return set_.load( std::memory_order_acquire ); | 24 | return set_.load( std::memory_order_acquire ); |
36 | #else | ||
37 | return set_; | ||
38 | #endif | ||
39 | } | 25 | } |
40 | 26 | ||
41 | private: | 27 | private: |
42 | #ifdef EFSW_USE_CXX11 | ||
43 | std::atomic<T> set_; | 28 | std::atomic<T> set_; |
44 | #else | ||
45 | volatile T set_; | ||
46 | #endif | ||
47 | }; | 29 | }; |
48 | 30 | ||
49 | } // namespace efsw | 31 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/Debug.cpp b/src/3rdParty/efsw/Debug.cpp index 18cfd31..18cfd31 100755..100644 --- a/src/3rdParty/efsw/Debug.cpp +++ b/src/3rdParty/efsw/Debug.cpp | |||
diff --git a/src/3rdParty/efsw/Debug.hpp b/src/3rdParty/efsw/Debug.hpp index 78d3557..fefaec4 100755..100644 --- a/src/3rdParty/efsw/Debug.hpp +++ b/src/3rdParty/efsw/Debug.hpp | |||
@@ -49,8 +49,10 @@ void efPRINTC( unsigned int cond, const char* format, ... ); | |||
49 | #define efDEBUGC( cond, format, args... ) \ | 49 | #define efDEBUGC( cond, format, args... ) \ |
50 | {} | 50 | {} |
51 | #else | 51 | #else |
52 | #define efDEBUG | 52 | #define efDEBUG( ... ) \ |
53 | #define efDEBUGC | 53 | {} |
54 | #define efDEBUGC( ... ) \ | ||
55 | {} | ||
54 | #endif | 56 | #endif |
55 | 57 | ||
56 | #endif | 58 | #endif |
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.cpp b/src/3rdParty/efsw/DirWatcherGeneric.cpp index 8b6bc8a..8b6bc8a 100755..100644 --- a/src/3rdParty/efsw/DirWatcherGeneric.cpp +++ b/src/3rdParty/efsw/DirWatcherGeneric.cpp | |||
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.hpp b/src/3rdParty/efsw/DirWatcherGeneric.hpp index ca52de7..ca52de7 100755..100644 --- a/src/3rdParty/efsw/DirWatcherGeneric.hpp +++ b/src/3rdParty/efsw/DirWatcherGeneric.hpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshot.cpp b/src/3rdParty/efsw/DirectorySnapshot.cpp index 6049e4a..f78475f 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshot.cpp +++ b/src/3rdParty/efsw/DirectorySnapshot.cpp | |||
@@ -44,7 +44,7 @@ void DirectorySnapshot::initFiles() { | |||
44 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); | 44 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); |
45 | 45 | ||
46 | FileInfoMap::iterator it = Files.begin(); | 46 | FileInfoMap::iterator it = Files.begin(); |
47 | std::list<std::string> eraseFiles; | 47 | std::vector<std::string> eraseFiles; |
48 | 48 | ||
49 | /// Remove all non regular files and non directories | 49 | /// Remove all non regular files and non directories |
50 | for ( ; it != Files.end(); it++ ) { | 50 | for ( ; it != Files.end(); it++ ) { |
@@ -53,7 +53,7 @@ void DirectorySnapshot::initFiles() { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); | 56 | for ( std::vector<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); |
57 | eit++ ) { | 57 | eit++ ) { |
58 | Files.erase( *eit ); | 58 | Files.erase( *eit ); |
59 | } | 59 | } |
diff --git a/src/3rdParty/efsw/DirectorySnapshot.hpp b/src/3rdParty/efsw/DirectorySnapshot.hpp index 0e60542..0e60542 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshot.hpp +++ b/src/3rdParty/efsw/DirectorySnapshot.hpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp index 37ee507..37ee507 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp index 26a29ec..26a29ec 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp | |||
diff --git a/src/3rdParty/efsw/FileInfo.cpp b/src/3rdParty/efsw/FileInfo.cpp index 072cd6d..707f617 100755..100644 --- a/src/3rdParty/efsw/FileInfo.cpp +++ b/src/3rdParty/efsw/FileInfo.cpp | |||
@@ -35,10 +35,6 @@ | |||
35 | #endif | 35 | #endif |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
39 | #include <filesystem> | ||
40 | #endif | ||
41 | |||
42 | namespace efsw { | 38 | namespace efsw { |
43 | 39 | ||
44 | bool FileInfo::exists( const std::string& filePath ) { | 40 | bool FileInfo::exists( const std::string& filePath ) { |
@@ -186,12 +182,14 @@ bool FileInfo::isLink() const { | |||
186 | std::string FileInfo::linksTo() { | 182 | std::string FileInfo::linksTo() { |
187 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | 183 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 |
188 | if ( isLink() ) { | 184 | if ( isLink() ) { |
189 | std::error_code ec; | 185 | char* ch = realpath( Filepath.c_str(), NULL ); |
190 | auto ch = std::filesystem::canonical( Filepath, ec ); | 186 | |
187 | if ( NULL != ch ) { | ||
188 | std::string tstr( ch ); | ||
191 | 189 | ||
192 | if ( !ec ) { | 190 | free( ch ); |
193 | 191 | ||
194 | return ch.string(); | 192 | return tstr; |
195 | } | 193 | } |
196 | } | 194 | } |
197 | #endif | 195 | #endif |
diff --git a/src/3rdParty/efsw/FileInfo.hpp b/src/3rdParty/efsw/FileInfo.hpp index f1bcf4b..1b55c35 100755..100644 --- a/src/3rdParty/efsw/FileInfo.hpp +++ b/src/3rdParty/efsw/FileInfo.hpp | |||
@@ -2,7 +2,7 @@ | |||
2 | #define EFSW_FILEINFO_HPP | 2 | #define EFSW_FILEINFO_HPP |
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | #include <list> | 5 | #include <vector> |
6 | #include <map> | 6 | #include <map> |
7 | #include <string> | 7 | #include <string> |
8 | 8 | ||
@@ -18,11 +18,11 @@ class FileInfo { | |||
18 | 18 | ||
19 | FileInfo(); | 19 | FileInfo(); |
20 | 20 | ||
21 | explicit FileInfo( const std::string& filepath ); | 21 | FileInfo( const std::string& filepath ); |
22 | 22 | ||
23 | FileInfo( const std::string& filepath, bool linkInfo ); | 23 | FileInfo( const std::string& filepath, bool linkInfo ); |
24 | 24 | ||
25 | FileInfo( const FileInfo& ) = default; | 25 | FileInfo(const FileInfo&) = default; |
26 | 26 | ||
27 | bool operator==( const FileInfo& Other ) const; | 27 | bool operator==( const FileInfo& Other ) const; |
28 | 28 | ||
@@ -58,8 +58,8 @@ class FileInfo { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | typedef std::map<std::string, FileInfo> FileInfoMap; | 60 | typedef std::map<std::string, FileInfo> FileInfoMap; |
61 | typedef std::list<FileInfo> FileInfoList; | 61 | typedef std::vector<FileInfo> FileInfoList; |
62 | typedef std::list<std::pair<std::string, FileInfo>> MovedList; | 62 | typedef std::vector<std::pair<std::string, FileInfo>> MovedList; |
63 | 63 | ||
64 | } // namespace efsw | 64 | } // namespace efsw |
65 | 65 | ||
diff --git a/src/3rdParty/efsw/FileSystem.cpp b/src/3rdParty/efsw/FileSystem.cpp index 867f120..1ed346c 100755..100644 --- a/src/3rdParty/efsw/FileSystem.cpp +++ b/src/3rdParty/efsw/FileSystem.cpp | |||
@@ -1,10 +1,19 @@ | |||
1 | #include <cstring> | ||
1 | #include <efsw/FileSystem.hpp> | 2 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/platform/platformimpl.hpp> | 3 | #include <efsw/platform/platformimpl.hpp> |
4 | #include <climits> | ||
3 | 5 | ||
4 | #if EFSW_OS == EFSW_OS_MACOSX | 6 | #if EFSW_OS == EFSW_OS_MACOSX |
5 | #include <CoreFoundation/CoreFoundation.h> | 7 | #include <CoreFoundation/CoreFoundation.h> |
6 | #endif | 8 | #endif |
7 | 9 | ||
10 | #if EFSW_OS == EFSW_OS_WIN | ||
11 | #ifndef WIN32_LEAN_AND_MEAN | ||
12 | #define WIN32_LEAN_AND_MEAN | ||
13 | #endif | ||
14 | #include <windows.h> | ||
15 | #endif | ||
16 | |||
8 | namespace efsw { | 17 | namespace efsw { |
9 | 18 | ||
10 | bool FileSystem::isDirectory( const std::string& path ) { | 19 | bool FileSystem::isDirectory( const std::string& path ) { |
@@ -26,13 +35,13 @@ bool FileSystem::slashAtEnd( std::string& dir ) { | |||
26 | } | 35 | } |
27 | 36 | ||
28 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) { | 37 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) { |
29 | if ( dir.size() > 1 && dir[dir.size() - 1] != getOSSlash() ) { | 38 | if ( dir.size() >= 1 && dir[dir.size() - 1] != getOSSlash() ) { |
30 | dir.push_back( getOSSlash() ); | 39 | dir.push_back( getOSSlash() ); |
31 | } | 40 | } |
32 | } | 41 | } |
33 | 42 | ||
34 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { | 43 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { |
35 | if ( dir.size() > 1 && dir[dir.size() - 1] == getOSSlash() ) { | 44 | if ( dir.size() >= 1 && dir[dir.size() - 1] == getOSSlash() ) { |
36 | dir.erase( dir.size() - 1 ); | 45 | dir.erase( dir.size() - 1 ); |
37 | } | 46 | } |
38 | } | 47 | } |
@@ -91,13 +100,30 @@ std::string FileSystem::precomposeFileName( const std::string& name ) { | |||
91 | 100 | ||
92 | CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); | 101 | CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); |
93 | 102 | ||
94 | char c_str[255 + 1]; | 103 | const char* c_str = CFStringGetCStringPtr( cfMutable, kCFStringEncodingUTF8 ); |
95 | CFStringGetCString( cfMutable, c_str, sizeof( c_str ) - 1, kCFStringEncodingUTF8 ); | 104 | if ( c_str != NULL ) { |
96 | 105 | std::string result( c_str ); | |
97 | CFRelease( cfStringRef ); | 106 | CFRelease( cfStringRef ); |
98 | CFRelease( cfMutable ); | 107 | CFRelease( cfMutable ); |
108 | return result; | ||
109 | } | ||
110 | CFIndex length = CFStringGetLength( cfMutable ); | ||
111 | CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ); | ||
112 | if ( maxSize == kCFNotFound ) { | ||
113 | CFRelease( cfStringRef ); | ||
114 | CFRelease( cfMutable ); | ||
115 | return std::string(); | ||
116 | } | ||
99 | 117 | ||
100 | return std::string( c_str ); | 118 | std::string result( maxSize + 1, '\0' ); |
119 | if ( CFStringGetCString( cfMutable, &result[0], result.size(), kCFStringEncodingUTF8 ) ) { | ||
120 | result.resize( std::strlen( result.c_str() ) ); | ||
121 | CFRelease( cfStringRef ); | ||
122 | CFRelease( cfMutable ); | ||
123 | } else { | ||
124 | result.clear(); | ||
125 | } | ||
126 | return result; | ||
101 | #else | 127 | #else |
102 | return name; | 128 | return name; |
103 | #endif | 129 | #endif |
@@ -115,4 +141,21 @@ std::string FileSystem::getCurrentWorkingDirectory() { | |||
115 | return Platform::FileSystem::getCurrentWorkingDirectory(); | 141 | return Platform::FileSystem::getCurrentWorkingDirectory(); |
116 | } | 142 | } |
117 | 143 | ||
144 | std::string FileSystem::getRealPath( const std::string& path ) { | ||
145 | std::string realPath; | ||
146 | #if defined( EFSW_PLATFORM_POSIX ) | ||
147 | char dir[PATH_MAX]; | ||
148 | realpath( path.c_str(), &dir[0] ); | ||
149 | realPath = std::string( dir ); | ||
150 | #elif EFSW_OS == EFSW_OS_WIN | ||
151 | wchar_t dir[_MAX_PATH + 1]; | ||
152 | GetFullPathNameW( String::fromUtf8( path ).toWideString().c_str(), _MAX_PATH, &dir[0], | ||
153 | nullptr ); | ||
154 | realPath = String( dir ).toUtf8(); | ||
155 | #else | ||
156 | #warning FileSystem::getRealPath() not implemented on this platform. | ||
157 | #endif | ||
158 | return realPath; | ||
159 | } | ||
160 | |||
118 | } // namespace efsw | 161 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileSystem.hpp b/src/3rdParty/efsw/FileSystem.hpp index 6c24386..1d66ece 100755..100644 --- a/src/3rdParty/efsw/FileSystem.hpp +++ b/src/3rdParty/efsw/FileSystem.hpp | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include <efsw/FileInfo.hpp> | 4 | #include <efsw/FileInfo.hpp> |
5 | #include <efsw/base.hpp> | 5 | #include <efsw/base.hpp> |
6 | #include <map> | ||
7 | 6 | ||
8 | namespace efsw { | 7 | namespace efsw { |
9 | 8 | ||
@@ -34,6 +33,9 @@ class FileSystem { | |||
34 | static bool changeWorkingDirectory( const std::string& path ); | 33 | static bool changeWorkingDirectory( const std::string& path ); |
35 | 34 | ||
36 | static std::string getCurrentWorkingDirectory(); | 35 | static std::string getCurrentWorkingDirectory(); |
36 | |||
37 | static std::string getRealPath( const std::string& path ); | ||
38 | |||
37 | }; | 39 | }; |
38 | 40 | ||
39 | } // namespace efsw | 41 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileWatcher.cpp b/src/3rdParty/efsw/FileWatcher.cpp index 696a46f..f45b243 100755..100644 --- a/src/3rdParty/efsw/FileWatcher.cpp +++ b/src/3rdParty/efsw/FileWatcher.cpp | |||
@@ -1,119 +1,120 @@ | |||
1 | #include <efsw/FileSystem.hpp> | 1 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/FileWatcherGeneric.hpp> | 2 | #include <efsw/FileWatcherGeneric.hpp> |
3 | #include <efsw/FileWatcherImpl.hpp> | 3 | #include <efsw/FileWatcherImpl.hpp> |
4 | #include <efsw/efsw.hpp> | 4 | #include <efsw/efsw.hpp> |
5 | 5 | ||
6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
7 | #include <efsw/FileWatcherWin32.hpp> | 7 | #include <efsw/FileWatcherWin32.hpp> |
8 | #define FILEWATCHER_IMPL FileWatcherWin32 | 8 | #define FILEWATCHER_IMPL FileWatcherWin32 |
9 | #define BACKEND_NAME "Win32" | 9 | #define BACKEND_NAME "Win32" |
10 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | 10 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY |
11 | #include <efsw/FileWatcherInotify.hpp> | 11 | #include <efsw/FileWatcherInotify.hpp> |
12 | #define FILEWATCHER_IMPL FileWatcherInotify | 12 | #define FILEWATCHER_IMPL FileWatcherInotify |
13 | #define BACKEND_NAME "Inotify" | 13 | #define BACKEND_NAME "Inotify" |
14 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE | 14 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE |
15 | #include <efsw/FileWatcherKqueue.hpp> | 15 | #include <efsw/FileWatcherKqueue.hpp> |
16 | #define FILEWATCHER_IMPL FileWatcherKqueue | 16 | #define FILEWATCHER_IMPL FileWatcherKqueue |
17 | #define BACKEND_NAME "Kqueue" | 17 | #define BACKEND_NAME "Kqueue" |
18 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | 18 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS |
19 | #include <efsw/FileWatcherFSEvents.hpp> | 19 | #include <efsw/FileWatcherFSEvents.hpp> |
20 | #define FILEWATCHER_IMPL FileWatcherFSEvents | 20 | #define FILEWATCHER_IMPL FileWatcherFSEvents |
21 | #define BACKEND_NAME "FSEvents" | 21 | #define BACKEND_NAME "FSEvents" |
22 | #else | 22 | #else |
23 | #define FILEWATCHER_IMPL FileWatcherGeneric | 23 | #define FILEWATCHER_IMPL FileWatcherGeneric |
24 | #define BACKEND_NAME "Generic" | 24 | #define BACKEND_NAME "Generic" |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #include <efsw/Debug.hpp> | 27 | #include <efsw/Debug.hpp> |
28 | 28 | ||
29 | namespace efsw { | 29 | namespace efsw { |
30 | 30 | ||
31 | FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | 31 | FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { |
32 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | 32 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); |
33 | 33 | ||
34 | mImpl = new FILEWATCHER_IMPL( this ); | 34 | mImpl = new FILEWATCHER_IMPL( this ); |
35 | 35 | ||
36 | if ( !mImpl->initOK() ) { | 36 | if ( !mImpl->initOK() ) { |
37 | efSAFE_DELETE( mImpl ); | 37 | efSAFE_DELETE( mImpl ); |
38 | 38 | ||
39 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | 39 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); |
40 | 40 | ||
41 | mImpl = new FileWatcherGeneric( this ); | 41 | mImpl = new FileWatcherGeneric( this ); |
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : | 45 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : |
46 | mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | 46 | mFollowSymlinks( false ), mOutOfScopeLinks( false ) { |
47 | if ( useGenericFileWatcher ) { | 47 | if ( useGenericFileWatcher ) { |
48 | efDEBUG( "Using backend: Generic\n" ); | 48 | efDEBUG( "Using backend: Generic\n" ); |
49 | 49 | ||
50 | mImpl = new FileWatcherGeneric( this ); | 50 | mImpl = new FileWatcherGeneric( this ); |
51 | } else { | 51 | } else { |
52 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | 52 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); |
53 | 53 | ||
54 | mImpl = new FILEWATCHER_IMPL( this ); | 54 | mImpl = new FILEWATCHER_IMPL( this ); |
55 | 55 | ||
56 | if ( !mImpl->initOK() ) { | 56 | if ( !mImpl->initOK() ) { |
57 | efSAFE_DELETE( mImpl ); | 57 | efSAFE_DELETE( mImpl ); |
58 | 58 | ||
59 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | 59 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); |
60 | 60 | ||
61 | mImpl = new FileWatcherGeneric( this ); | 61 | mImpl = new FileWatcherGeneric( this ); |
62 | } | 62 | } |
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | FileWatcher::~FileWatcher() { | 66 | FileWatcher::~FileWatcher() { |
67 | efSAFE_DELETE( mImpl ); | 67 | efSAFE_DELETE( mImpl ); |
68 | } | 68 | } |
69 | 69 | ||
70 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { | 70 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { |
71 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | 71 | return addWatch( directory, watcher, false, {} ); |
72 | return mImpl->addWatch( directory, watcher, false ); | 72 | } |
73 | } else { | 73 | |
74 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | 74 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, |
75 | } | 75 | bool recursive ) { |
76 | } | 76 | return addWatch( directory, watcher, recursive, {} ); |
77 | 77 | } | |
78 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, | 78 | |
79 | bool recursive ) { | 79 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, |
80 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | 80 | bool recursive, const std::vector<WatcherOption>& options ) { |
81 | return mImpl->addWatch( directory, watcher, recursive ); | 81 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { |
82 | } else { | 82 | return mImpl->addWatch( directory, watcher, recursive, options ); |
83 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | 83 | } else { |
84 | } | 84 | return Errors::Log::createLastError( Errors::FileRemote, directory ); |
85 | } | 85 | } |
86 | 86 | } | |
87 | void FileWatcher::removeWatch( const std::string& directory ) { | 87 | |
88 | mImpl->removeWatch( directory ); | 88 | void FileWatcher::removeWatch( const std::string& directory ) { |
89 | } | 89 | mImpl->removeWatch( directory ); |
90 | 90 | } | |
91 | void FileWatcher::removeWatch( WatchID watchid ) { | 91 | |
92 | mImpl->removeWatch( watchid ); | 92 | void FileWatcher::removeWatch( WatchID watchid ) { |
93 | } | 93 | mImpl->removeWatch( watchid ); |
94 | 94 | } | |
95 | void FileWatcher::watch() { | 95 | |
96 | mImpl->watch(); | 96 | void FileWatcher::watch() { |
97 | } | 97 | mImpl->watch(); |
98 | 98 | } | |
99 | std::list<std::string> FileWatcher::directories() { | 99 | |
100 | return mImpl->directories(); | 100 | std::vector<std::string> FileWatcher::directories() { |
101 | } | 101 | return mImpl->directories(); |
102 | 102 | } | |
103 | void FileWatcher::followSymlinks( bool follow ) { | 103 | |
104 | mFollowSymlinks = follow; | 104 | void FileWatcher::followSymlinks( bool follow ) { |
105 | } | 105 | mFollowSymlinks = follow; |
106 | 106 | } | |
107 | const bool& FileWatcher::followSymlinks() const { | 107 | |
108 | return mFollowSymlinks; | 108 | const bool& FileWatcher::followSymlinks() const { |
109 | } | 109 | return mFollowSymlinks; |
110 | 110 | } | |
111 | void FileWatcher::allowOutOfScopeLinks( bool allow ) { | 111 | |
112 | mOutOfScopeLinks = allow; | 112 | void FileWatcher::allowOutOfScopeLinks( bool allow ) { |
113 | } | 113 | mOutOfScopeLinks = allow; |
114 | 114 | } | |
115 | const bool& FileWatcher::allowOutOfScopeLinks() const { | 115 | |
116 | return mOutOfScopeLinks; | 116 | const bool& FileWatcher::allowOutOfScopeLinks() const { |
117 | } | 117 | return mOutOfScopeLinks; |
118 | 118 | } | |
119 | } // namespace efsw | 119 | |
120 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherCWrapper.cpp b/src/3rdParty/efsw/FileWatcherCWrapper.cpp index 5c49a66..8712d6e 100755..100644 --- a/src/3rdParty/efsw/FileWatcherCWrapper.cpp +++ b/src/3rdParty/efsw/FileWatcherCWrapper.cpp | |||
@@ -28,12 +28,12 @@ class Watcher_CAPI : public efsw::FileWatchListener { | |||
28 | */ | 28 | */ |
29 | static std::vector<Watcher_CAPI*> g_callbacks; | 29 | static std::vector<Watcher_CAPI*> g_callbacks; |
30 | 30 | ||
31 | Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) { | 31 | Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) { |
32 | for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); | 32 | for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); |
33 | ++i ) { | 33 | ++i ) { |
34 | Watcher_CAPI* callback = *i; | 34 | Watcher_CAPI* callback = *i; |
35 | 35 | ||
36 | if ( callback->mFn == fn && callback->mWatcher == watcher ) | 36 | if ( callback->mFn == fn && callback->mWatcher == watcher && callback->mParam == param ) |
37 | return *i; | 37 | return *i; |
38 | } | 38 | } |
39 | 39 | ||
@@ -71,17 +71,35 @@ const char* efsw_getlasterror() { | |||
71 | return log_str.c_str(); | 71 | return log_str.c_str(); |
72 | } | 72 | } |
73 | 73 | ||
74 | EFSW_API void efsw_clearlasterror() { | ||
75 | efsw::Errors::Log::clearLastError(); | ||
76 | } | ||
77 | |||
74 | efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, | 78 | efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, |
75 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { | 79 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { |
76 | Watcher_CAPI* callback = find_callback( watcher, callback_fn ); | 80 | return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param ); |
81 | } | ||
82 | |||
83 | efsw_watchid efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory, | ||
84 | efsw_pfn_fileaction_callback callback_fn, int recursive, | ||
85 | efsw_watcher_option *options, int options_number, | ||
86 | void* param) { | ||
87 | Watcher_CAPI* callback = find_callback( watcher, callback_fn, param ); | ||
77 | 88 | ||
78 | if ( callback == NULL ) { | 89 | if ( callback == NULL ) { |
79 | callback = new Watcher_CAPI( watcher, callback_fn, param ); | 90 | callback = new Watcher_CAPI( watcher, callback_fn, param ); |
80 | g_callbacks.push_back( callback ); | 91 | g_callbacks.push_back( callback ); |
81 | } | 92 | } |
82 | 93 | ||
94 | std::vector<efsw::WatcherOption> watcher_options{}; | ||
95 | for ( int i = 0; i < options_number; i++ ) { | ||
96 | efsw_watcher_option* option = &options[i]; | ||
97 | watcher_options.emplace_back( efsw::WatcherOption{ | ||
98 | static_cast<efsw::Option>(option->option), option->value } ); | ||
99 | } | ||
100 | |||
83 | return ( (efsw::FileWatcher*)watcher ) | 101 | return ( (efsw::FileWatcher*)watcher ) |
84 | ->addWatch( std::string( directory ), callback, TOBOOL( recursive ) ); | 102 | ->addWatch( std::string( directory ), callback, TOBOOL( recursive ), watcher_options ); |
85 | } | 103 | } |
86 | 104 | ||
87 | void efsw_removewatch( efsw_watcher watcher, const char* directory ) { | 105 | void efsw_removewatch( efsw_watcher watcher, const char* directory ) { |
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.cpp b/src/3rdParty/efsw/FileWatcherFSEvents.cpp index bcfdbe6..70ec2b1 100755..100644 --- a/src/3rdParty/efsw/FileWatcherFSEvents.cpp +++ b/src/3rdParty/efsw/FileWatcherFSEvents.cpp | |||
@@ -41,6 +41,32 @@ bool FileWatcherFSEvents::isGranular() { | |||
41 | return getOSXReleaseNumber() >= 11; | 41 | return getOSXReleaseNumber() >= 11; |
42 | } | 42 | } |
43 | 43 | ||
44 | static std::string convertCFStringToStdString( CFStringRef cfString ) { | ||
45 | // Try to get the C string pointer directly | ||
46 | const char* cStr = CFStringGetCStringPtr( cfString, kCFStringEncodingUTF8 ); | ||
47 | |||
48 | if ( cStr ) { | ||
49 | // If the pointer is valid, directly return a std::string from it | ||
50 | return std::string( cStr ); | ||
51 | } else { | ||
52 | // If not, manually convert it | ||
53 | CFIndex length = CFStringGetLength( cfString ); | ||
54 | CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) + | ||
55 | 1; // +1 for null terminator | ||
56 | |||
57 | char* buffer = new char[maxSize]; | ||
58 | |||
59 | if ( CFStringGetCString( cfString, buffer, maxSize, kCFStringEncodingUTF8 ) ) { | ||
60 | std::string result( buffer ); | ||
61 | delete[] buffer; | ||
62 | return result; | ||
63 | } else { | ||
64 | delete[] buffer; | ||
65 | return ""; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
44 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData, | 70 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData, |
45 | size_t numEvents, void* eventPaths, | 71 | size_t numEvents, void* eventPaths, |
46 | const FSEventStreamEventFlags eventFlags[], | 72 | const FSEventStreamEventFlags eventFlags[], |
@@ -51,8 +77,24 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, | |||
51 | events.reserve( numEvents ); | 77 | events.reserve( numEvents ); |
52 | 78 | ||
53 | for ( size_t i = 0; i < numEvents; i++ ) { | 79 | for ( size_t i = 0; i < numEvents; i++ ) { |
54 | events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i], | 80 | if ( isGranular() ) { |
55 | (Uint64)eventIds[i] ) ); | 81 | CFDictionaryRef pathInfoDict = |
82 | static_cast<CFDictionaryRef>( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) ); | ||
83 | CFStringRef path = static_cast<CFStringRef>( | ||
84 | CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) ); | ||
85 | CFNumberRef cfInode = static_cast<CFNumberRef>( | ||
86 | CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedFileIDKey ) ); | ||
87 | |||
88 | if ( cfInode ) { | ||
89 | unsigned long inode = 0; | ||
90 | CFNumberGetValue( cfInode, kCFNumberLongType, &inode ); | ||
91 | events.push_back( FSEvent( convertCFStringToStdString( path ), (long)eventFlags[i], | ||
92 | (Uint64)eventIds[i], inode ) ); | ||
93 | } | ||
94 | } else { | ||
95 | events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), | ||
96 | (long)eventFlags[i], (Uint64)eventIds[i] ) ); | ||
97 | } | ||
56 | } | 98 | } |
57 | 99 | ||
58 | watcher->handleActions( events ); | 100 | watcher->handleActions( events ); |
@@ -63,7 +105,7 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, | |||
63 | } | 105 | } |
64 | 106 | ||
65 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : | 107 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : |
66 | FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) { | 108 | FileWatcherImpl( parent ), mLastWatchID( 0 ) { |
67 | mInitOK = true; | 109 | mInitOK = true; |
68 | 110 | ||
69 | watch(); | 111 | watch(); |
@@ -72,10 +114,7 @@ FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : | |||
72 | FileWatcherFSEvents::~FileWatcherFSEvents() { | 114 | FileWatcherFSEvents::~FileWatcherFSEvents() { |
73 | mInitOK = false; | 115 | mInitOK = false; |
74 | 116 | ||
75 | if ( mRunLoopRef.load() ) | 117 | mWatchCond.notify_all(); |
76 | CFRunLoopStop( mRunLoopRef.load() ); | ||
77 | |||
78 | efSAFE_DELETE( mThread ); | ||
79 | 118 | ||
80 | WatchMap::iterator iter = mWatches.begin(); | 119 | WatchMap::iterator iter = mWatches.begin(); |
81 | 120 | ||
@@ -84,18 +123,11 @@ FileWatcherFSEvents::~FileWatcherFSEvents() { | |||
84 | 123 | ||
85 | efSAFE_DELETE( watch ); | 124 | efSAFE_DELETE( watch ); |
86 | } | 125 | } |
87 | |||
88 | mWatches.clear(); | ||
89 | } | 126 | } |
90 | 127 | ||
91 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, | 128 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, |
92 | bool recursive ) { | 129 | bool recursive, const std::vector<WatcherOption>& options ) { |
93 | /// Wait to the RunLoopRef to be ready | 130 | std::string dir( FileSystem::getRealPath( directory ) ); |
94 | while ( NULL == mRunLoopRef.load() ) { | ||
95 | System::sleep( 1 ); | ||
96 | } | ||
97 | |||
98 | std::string dir( directory ); | ||
99 | 131 | ||
100 | FileInfo fi( dir ); | 132 | FileInfo fi( dir ); |
101 | 133 | ||
@@ -135,12 +167,18 @@ WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchLi | |||
135 | pWatch->Directory = dir; | 167 | pWatch->Directory = dir; |
136 | pWatch->Recursive = recursive; | 168 | pWatch->Recursive = recursive; |
137 | pWatch->FWatcher = this; | 169 | pWatch->FWatcher = this; |
170 | pWatch->ModifiedFlags = | ||
171 | getOptionValue( options, Option::MacModifiedFilter, efswFSEventsModified ); | ||
172 | pWatch->SanitizeEvents = getOptionValue( options, Option::MacSanitizeEvents, 0 ) != 0; | ||
138 | 173 | ||
139 | pWatch->init(); | 174 | pWatch->init(); |
140 | 175 | ||
141 | Lock lock( mWatchesLock ); | 176 | { |
142 | mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); | 177 | Lock lock( mWatchesLock ); |
178 | mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); | ||
179 | } | ||
143 | 180 | ||
181 | mWatchCond.notify_all(); | ||
144 | return pWatch->ID; | 182 | return pWatch->ID; |
145 | } | 183 | } |
146 | 184 | ||
@@ -174,50 +212,20 @@ void FileWatcherFSEvents::removeWatch( WatchID watchid ) { | |||
174 | efSAFE_DELETE( watch ); | 212 | efSAFE_DELETE( watch ); |
175 | } | 213 | } |
176 | 214 | ||
177 | void FileWatcherFSEvents::watch() { | 215 | void FileWatcherFSEvents::watch() {} |
178 | if ( NULL == mThread ) { | ||
179 | mThread = new Thread( &FileWatcherFSEvents::run, this ); | ||
180 | mThread->launch(); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | void FileWatcherFSEvents::run() { | ||
185 | mRunLoopRef = CFRunLoopGetCurrent(); | ||
186 | |||
187 | while ( mInitOK ) { | ||
188 | mNeedInitMutex.lock(); | ||
189 | |||
190 | if ( !mNeedInit.empty() ) { | ||
191 | for ( std::vector<WatcherFSEvents*>::iterator it = mNeedInit.begin(); | ||
192 | it != mNeedInit.end(); ++it ) { | ||
193 | ( *it )->initAsync(); | ||
194 | } | ||
195 | |||
196 | mNeedInit.clear(); | ||
197 | } | ||
198 | |||
199 | mNeedInitMutex.unlock(); | ||
200 | |||
201 | if ( mWatches.empty() ) { | ||
202 | System::sleep( 100 ); | ||
203 | } else { | ||
204 | CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut ); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | mRunLoopRef = NULL; | ||
209 | } | ||
210 | 216 | ||
211 | void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, | 217 | void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, |
212 | unsigned long /*action*/, std::string /*oldFilename*/ ) { | 218 | unsigned long /*action*/, std::string /*oldFilename*/ ) { |
213 | /// Not used | 219 | /// Not used |
214 | } | 220 | } |
215 | 221 | ||
216 | std::list<std::string> FileWatcherFSEvents::directories() { | 222 | std::vector<std::string> FileWatcherFSEvents::directories() { |
217 | std::list<std::string> dirs; | 223 | std::vector<std::string> dirs; |
218 | 224 | ||
219 | Lock lock( mWatchesLock ); | 225 | Lock lock( mWatchesLock ); |
220 | 226 | ||
227 | dirs.reserve( mWatches.size() ); | ||
228 | |||
221 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 229 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
222 | dirs.push_back( std::string( it->second->Directory ) ); | 230 | dirs.push_back( std::string( it->second->Directory ) ); |
223 | } | 231 | } |
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.hpp b/src/3rdParty/efsw/FileWatcherFSEvents.hpp index 5279847..daa538c 100755..100644 --- a/src/3rdParty/efsw/FileWatcherFSEvents.hpp +++ b/src/3rdParty/efsw/FileWatcherFSEvents.hpp | |||
@@ -7,33 +7,15 @@ | |||
7 | 7 | ||
8 | #include <CoreFoundation/CoreFoundation.h> | 8 | #include <CoreFoundation/CoreFoundation.h> |
9 | #include <CoreServices/CoreServices.h> | 9 | #include <CoreServices/CoreServices.h> |
10 | #include <dispatch/dispatch.h> | ||
10 | #include <efsw/WatcherFSEvents.hpp> | 11 | #include <efsw/WatcherFSEvents.hpp> |
11 | #include <list> | ||
12 | #include <map> | 12 | #include <map> |
13 | #include <vector> | 13 | #include <vector> |
14 | #include <condition_variable> | ||
15 | #include <mutex> | ||
14 | 16 | ||
15 | namespace efsw { | 17 | namespace efsw { |
16 | 18 | ||
17 | /* OSX < 10.7 has no file events */ | ||
18 | /* So i declare the events constants */ | ||
19 | enum FSEventEvents { | ||
20 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, | ||
21 | efswFSEventStreamEventFlagItemCreated = 0x00000100, | ||
22 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, | ||
23 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | ||
24 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, | ||
25 | efswFSEventStreamEventFlagItemModified = 0x00001000, | ||
26 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | ||
27 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, | ||
28 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, | ||
29 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, | ||
30 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, | ||
31 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, | ||
32 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | | ||
33 | efswFSEventStreamEventFlagItemModified | | ||
34 | efswFSEventStreamEventFlagItemInodeMetaMod | ||
35 | }; | ||
36 | |||
37 | /// Implementation for Win32 based on ReadDirectoryChangesW. | 19 | /// Implementation for Win32 based on ReadDirectoryChangesW. |
38 | /// @class FileWatcherFSEvents | 20 | /// @class FileWatcherFSEvents |
39 | class FileWatcherFSEvents : public FileWatcherImpl { | 21 | class FileWatcherFSEvents : public FileWatcherImpl { |
@@ -52,48 +34,43 @@ class FileWatcherFSEvents : public FileWatcherImpl { | |||
52 | 34 | ||
53 | /// Add a directory watch | 35 | /// Add a directory watch |
54 | /// On error returns WatchID with Error type. | 36 | /// On error returns WatchID with Error type. |
55 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 37 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
38 | const std::vector<WatcherOption> &options ) override; | ||
56 | 39 | ||
57 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 40 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
58 | void removeWatch( const std::string& directory ); | 41 | void removeWatch( const std::string& directory ) override; |
59 | 42 | ||
60 | /// Remove a directory watch. This is a map lookup O(logn). | 43 | /// Remove a directory watch. This is a map lookup O(logn). |
61 | void removeWatch( WatchID watchid ); | 44 | void removeWatch( WatchID watchid ) override; |
62 | 45 | ||
63 | /// Updates the watcher. Must be called often. | 46 | /// Updates the watcher. Must be called often. |
64 | void watch(); | 47 | void watch() override; |
65 | 48 | ||
66 | /// Handles the action | 49 | /// Handles the action |
67 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 50 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
68 | std::string oldFilename = "" ); | 51 | std::string oldFilename = "" ) override; |
69 | 52 | ||
70 | /// @return Returns a list of the directories that are being watched | 53 | /// @return Returns a list of the directories that are being watched |
71 | std::list<std::string> directories(); | 54 | std::vector<std::string> directories() override; |
72 | 55 | ||
73 | protected: | 56 | protected: |
74 | static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, | 57 | static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, |
75 | void* eventPaths, const FSEventStreamEventFlags eventFlags[], | 58 | void* eventPaths, const FSEventStreamEventFlags eventFlags[], |
76 | const FSEventStreamEventId eventIds[] ); | 59 | const FSEventStreamEventId eventIds[] ); |
77 | 60 | ||
78 | Atomic<CFRunLoopRef> mRunLoopRef; | ||
79 | |||
80 | /// Vector of WatcherWin32 pointers | 61 | /// Vector of WatcherWin32 pointers |
81 | WatchMap mWatches; | 62 | WatchMap mWatches; |
82 | 63 | ||
83 | /// The last watchid | 64 | /// The last watchid |
84 | WatchID mLastWatchID; | 65 | WatchID mLastWatchID; |
85 | 66 | ||
86 | Thread* mThread; | ||
87 | |||
88 | Mutex mWatchesLock; | 67 | Mutex mWatchesLock; |
89 | 68 | ||
90 | bool pathInWatches( const std::string& path ); | 69 | bool pathInWatches( const std::string& path ) override; |
91 | 70 | ||
92 | std::vector<WatcherFSEvents*> mNeedInit; | 71 | std::mutex mWatchesMutex; |
93 | Mutex mNeedInitMutex; | 72 | std::condition_variable mWatchCond; |
94 | 73 | ||
95 | private: | ||
96 | void run(); | ||
97 | }; | 74 | }; |
98 | 75 | ||
99 | } // namespace efsw | 76 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp index 074cff1..468d27c 100755..100644 --- a/src/3rdParty/efsw/FileWatcherGeneric.cpp +++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp | |||
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, | 27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, |
28 | bool recursive ) { | 28 | bool recursive, const std::vector<WatcherOption>& /*options*/ ) { |
29 | std::string dir( directory ); | 29 | std::string dir( directory ); |
30 | 30 | ||
31 | FileSystem::dirAddSlashAtEnd( dir ); | 31 | FileSystem::dirAddSlashAtEnd( dir ); |
@@ -127,11 +127,13 @@ void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned lo | |||
127 | /// Not used | 127 | /// Not used |
128 | } | 128 | } |
129 | 129 | ||
130 | std::list<std::string> FileWatcherGeneric::directories() { | 130 | std::vector<std::string> FileWatcherGeneric::directories() { |
131 | std::list<std::string> dirs; | 131 | std::vector<std::string> dirs; |
132 | 132 | ||
133 | Lock lock( mWatchesLock ); | 133 | Lock lock( mWatchesLock ); |
134 | 134 | ||
135 | dirs.reserve( mWatches.size() ); | ||
136 | |||
135 | WatchList::iterator it = mWatches.begin(); | 137 | WatchList::iterator it = mWatches.begin(); |
136 | 138 | ||
137 | for ( ; it != mWatches.end(); ++it ) { | 139 | for ( ; it != mWatches.end(); ++it ) { |
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.hpp b/src/3rdParty/efsw/FileWatcherGeneric.hpp index 4cb0b67..47f7e04 100755..100644 --- a/src/3rdParty/efsw/FileWatcherGeneric.hpp +++ b/src/3rdParty/efsw/FileWatcherGeneric.hpp | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <efsw/DirWatcherGeneric.hpp> | 4 | #include <efsw/DirWatcherGeneric.hpp> |
5 | #include <efsw/FileWatcherImpl.hpp> | 5 | #include <efsw/FileWatcherImpl.hpp> |
6 | #include <efsw/WatcherGeneric.hpp> | 6 | #include <efsw/WatcherGeneric.hpp> |
7 | #include <list> | 7 | #include <vector> |
8 | 8 | ||
9 | namespace efsw { | 9 | namespace efsw { |
10 | 10 | ||
@@ -12,7 +12,7 @@ namespace efsw { | |||
12 | /// @class FileWatcherGeneric | 12 | /// @class FileWatcherGeneric |
13 | class FileWatcherGeneric : public FileWatcherImpl { | 13 | class FileWatcherGeneric : public FileWatcherImpl { |
14 | public: | 14 | public: |
15 | typedef std::list<WatcherGeneric*> WatchList; | 15 | typedef std::vector<WatcherGeneric*> WatchList; |
16 | 16 | ||
17 | FileWatcherGeneric( FileWatcher* parent ); | 17 | FileWatcherGeneric( FileWatcher* parent ); |
18 | 18 | ||
@@ -20,23 +20,24 @@ class FileWatcherGeneric : public FileWatcherImpl { | |||
20 | 20 | ||
21 | /// Add a directory watch | 21 | /// Add a directory watch |
22 | /// On error returns WatchID with Error type. | 22 | /// On error returns WatchID with Error type. |
23 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 23 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
24 | const std::vector<WatcherOption> &options ) override; | ||
24 | 25 | ||
25 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 26 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
26 | void removeWatch( const std::string& directory ); | 27 | void removeWatch( const std::string& directory ) override; |
27 | 28 | ||
28 | /// Remove a directory watch. This is a map lookup O(logn). | 29 | /// Remove a directory watch. This is a map lookup O(logn). |
29 | void removeWatch( WatchID watchid ); | 30 | void removeWatch( WatchID watchid ) override; |
30 | 31 | ||
31 | /// Updates the watcher. Must be called often. | 32 | /// Updates the watcher. Must be called often. |
32 | void watch(); | 33 | void watch() override; |
33 | 34 | ||
34 | /// Handles the action | 35 | /// Handles the action |
35 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 36 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
36 | std::string oldFilename = "" ); | 37 | std::string oldFilename = "" ) override; |
37 | 38 | ||
38 | /// @return Returns a list of the directories that are being watched | 39 | /// @return Returns a list of the directories that are being watched |
39 | std::list<std::string> directories(); | 40 | std::vector<std::string> directories() override; |
40 | 41 | ||
41 | protected: | 42 | protected: |
42 | Thread* mThread; | 43 | Thread* mThread; |
@@ -49,7 +50,7 @@ class FileWatcherGeneric : public FileWatcherImpl { | |||
49 | 50 | ||
50 | Mutex mWatchesLock; | 51 | Mutex mWatchesLock; |
51 | 52 | ||
52 | bool pathInWatches( const std::string& path ); | 53 | bool pathInWatches( const std::string& path ) override; |
53 | 54 | ||
54 | private: | 55 | private: |
55 | void run(); | 56 | void run(); |
diff --git a/src/3rdParty/efsw/FileWatcherImpl.cpp b/src/3rdParty/efsw/FileWatcherImpl.cpp index f6b86a5..bf69a45 100755..100644 --- a/src/3rdParty/efsw/FileWatcherImpl.cpp +++ b/src/3rdParty/efsw/FileWatcherImpl.cpp | |||
@@ -1,23 +1,34 @@ | |||
1 | #include <efsw/FileWatcherImpl.hpp> | 1 | #include <efsw/FileWatcherImpl.hpp> |
2 | #include <efsw/String.hpp> | 2 | #include <efsw/String.hpp> |
3 | #include <efsw/System.hpp> | 3 | #include <efsw/System.hpp> |
4 | 4 | ||
5 | namespace efsw { | 5 | namespace efsw { |
6 | 6 | ||
7 | FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : | 7 | FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : |
8 | mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { | 8 | mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { |
9 | System::maxFD(); | 9 | System::maxFD(); |
10 | } | 10 | } |
11 | 11 | ||
12 | FileWatcherImpl::~FileWatcherImpl() {} | 12 | FileWatcherImpl::~FileWatcherImpl() {} |
13 | 13 | ||
14 | bool FileWatcherImpl::initOK() { | 14 | bool FileWatcherImpl::initOK() { |
15 | return static_cast<bool>( mInitOK ); | 15 | return static_cast<bool>( mInitOK ); |
16 | } | 16 | } |
17 | 17 | ||
18 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { | 18 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { |
19 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || | 19 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || |
20 | -1 != String::strStartsWith( curPath, link ); | 20 | -1 != String::strStartsWith( curPath, link ); |
21 | } | 21 | } |
22 | 22 | ||
23 | } // namespace efsw | 23 | int FileWatcherImpl::getOptionValue( const std::vector<WatcherOption>& options, Option option, |
24 | int defaultValue ) { | ||
25 | for ( size_t i = 0; i < options.size(); i++ ) { | ||
26 | if ( options[i].mOption == option ) { | ||
27 | return options[i].mValue; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | return defaultValue; | ||
32 | } | ||
33 | |||
34 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherImpl.hpp b/src/3rdParty/efsw/FileWatcherImpl.hpp index ea1beb8..a6ec472 100755..100644 --- a/src/3rdParty/efsw/FileWatcherImpl.hpp +++ b/src/3rdParty/efsw/FileWatcherImpl.hpp | |||
@@ -1,57 +1,64 @@ | |||
1 | #ifndef EFSW_FILEWATCHERIMPL_HPP | 1 | #ifndef EFSW_FILEWATCHERIMPL_HPP |
2 | #define EFSW_FILEWATCHERIMPL_HPP | 2 | #define EFSW_FILEWATCHERIMPL_HPP |
3 | 3 | ||
4 | #include <efsw/Atomic.hpp> | 4 | #include <efsw/Atomic.hpp> |
5 | #include <efsw/Mutex.hpp> | 5 | #include <efsw/Mutex.hpp> |
6 | #include <efsw/Thread.hpp> | 6 | #include <efsw/Thread.hpp> |
7 | #include <efsw/Watcher.hpp> | 7 | #include <efsw/Watcher.hpp> |
8 | #include <efsw/base.hpp> | 8 | #include <efsw/base.hpp> |
9 | #include <efsw/efsw.hpp> | 9 | #include <efsw/efsw.hpp> |
10 | 10 | ||
11 | namespace efsw { | 11 | namespace efsw { |
12 | 12 | ||
13 | class FileWatcherImpl { | 13 | class FileWatcherImpl { |
14 | public: | 14 | public: |
15 | FileWatcherImpl( FileWatcher* parent ); | 15 | FileWatcherImpl( FileWatcher* parent ); |
16 | 16 | ||
17 | virtual ~FileWatcherImpl(); | 17 | virtual ~FileWatcherImpl(); |
18 | 18 | ||
19 | /// Add a directory watch | 19 | /// Add a directory watch |
20 | /// On error returns WatchID with Error type. | 20 | /// On error returns WatchID with Error type. |
21 | virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, | 21 | virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, |
22 | bool recursive ) = 0; | 22 | bool recursive, const std::vector<WatcherOption>& options = {} ) = 0; |
23 | 23 | ||
24 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 24 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
25 | virtual void removeWatch( const std::string& directory ) = 0; | 25 | virtual void removeWatch( const std::string& directory ) = 0; |
26 | 26 | ||
27 | /// Remove a directory watch. This is a map lookup O(logn). | 27 | /// Remove a directory watch. This is a map lookup O(logn). |
28 | virtual void removeWatch( WatchID watchid ) = 0; | 28 | virtual void removeWatch( WatchID watchid ) = 0; |
29 | 29 | ||
30 | /// Updates the watcher. Must be called often. | 30 | /// Updates the watcher. Must be called often. |
31 | virtual void watch() = 0; | 31 | virtual void watch() = 0; |
32 | 32 | ||
33 | /// Handles the action | 33 | /// Handles the action |
34 | virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 34 | virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
35 | std::string oldFilename = "" ) = 0; | 35 | std::string oldFilename = "" ) = 0; |
36 | 36 | ||
37 | /// @return Returns a list of the directories that are being watched | 37 | /// @return Returns a list of the directories that are being watched |
38 | virtual std::list<std::string> directories() = 0; | 38 | virtual std::vector<std::string> directories() = 0; |
39 | 39 | ||
40 | /// @return true if the backend init successfully | 40 | /// @return true if the backend init successfully |
41 | virtual bool initOK(); | 41 | virtual bool initOK(); |
42 | 42 | ||
43 | /// @return If the link is allowed according to the current path and the state of out scope | 43 | /// @return If the link is allowed according to the current path and the state of out scope |
44 | /// links | 44 | /// links |
45 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); | 45 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); |
46 | 46 | ||
47 | /// Search if a directory already exists in the watches | 47 | /// Search if a directory already exists in the watches |
48 | virtual bool pathInWatches( const std::string& path ) = 0; | 48 | virtual bool pathInWatches( const std::string& path ) = 0; |
49 | 49 | ||
50 | FileWatcher* mFileWatcher; | 50 | protected: |
51 | Atomic<bool> mInitOK; | 51 | friend class FileWatcher; |
52 | bool mIsGeneric; | 52 | friend class DirWatcherGeneric; |
53 | }; | 53 | |
54 | 54 | FileWatcher* mFileWatcher; | |
55 | } // namespace efsw | 55 | Atomic<bool> mInitOK; |
56 | 56 | bool mIsGeneric; | |
57 | #endif | 57 | |
58 | int getOptionValue( const std::vector<WatcherOption>& options, Option option, | ||
59 | int defaultValue ); | ||
60 | }; | ||
61 | |||
62 | } // namespace efsw | ||
63 | |||
64 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp index e0da76b..1ec3d48 100755..100644 --- a/src/3rdParty/efsw/FileWatcherInotify.cpp +++ b/src/3rdParty/efsw/FileWatcherInotify.cpp | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <algorithm> | ||
1 | #include <efsw/FileWatcherInotify.hpp> | 2 | #include <efsw/FileWatcherInotify.hpp> |
2 | 3 | ||
3 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | 4 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY |
@@ -26,7 +27,7 @@ | |||
26 | namespace efsw { | 27 | namespace efsw { |
27 | 28 | ||
28 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | 29 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : |
29 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { | 30 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) { |
30 | mFD = inotify_init(); | 31 | mFD = inotify_init(); |
31 | 32 | ||
32 | if ( mFD < 0 ) { | 33 | if ( mFD < 0 ) { |
@@ -38,13 +39,20 @@ FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | |||
38 | 39 | ||
39 | FileWatcherInotify::~FileWatcherInotify() { | 40 | FileWatcherInotify::~FileWatcherInotify() { |
40 | mInitOK = false; | 41 | mInitOK = false; |
41 | 42 | // There is deadlock when release FileWatcherInotify instance since its handAction | |
43 | // function is still running and hangs in requiring lock without init lock captured. | ||
44 | while ( mIsTakingAction ) { | ||
45 | // It'd use condition-wait instead of sleep. Actually efsw has no such | ||
46 | // implementation so we just skip and sleep while for that to avoid deadlock. | ||
47 | usleep( 1000 ); | ||
48 | }; | ||
42 | Lock initLock( mInitLock ); | 49 | Lock initLock( mInitLock ); |
43 | 50 | ||
44 | efSAFE_DELETE( mThread ); | 51 | efSAFE_DELETE( mThread ); |
45 | 52 | ||
46 | Lock l( mWatchesLock ); | 53 | Lock l( mWatchesLock ); |
47 | Lock l2( mRealWatchesLock ); | 54 | Lock l2( mRealWatchesLock ); |
55 | |||
48 | WatchMap::iterator iter = mWatches.begin(); | 56 | WatchMap::iterator iter = mWatches.begin(); |
49 | WatchMap::iterator end = mWatches.end(); | 57 | WatchMap::iterator end = mWatches.end(); |
50 | 58 | ||
@@ -61,15 +69,17 @@ FileWatcherInotify::~FileWatcherInotify() { | |||
61 | } | 69 | } |
62 | 70 | ||
63 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | 71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, |
64 | bool recursive ) { | 72 | bool recursive, const std::vector<WatcherOption>& options ) { |
65 | if ( !mInitOK ) | 73 | if ( !mInitOK ) |
66 | return Errors::Log::createLastError( Errors::Unspecified, directory ); | 74 | return Errors::Log::createLastError( Errors::Unspecified, directory ); |
67 | Lock initLock( mInitLock ); | 75 | Lock initLock( mInitLock ); |
68 | return addWatch( directory, watcher, recursive, NULL ); | 76 | bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0; |
77 | return addWatch( directory, watcher, recursive, syntheticEvents, NULL ); | ||
69 | } | 78 | } |
70 | 79 | ||
71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | 80 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, |
72 | bool recursive, WatcherInotify* parent ) { | 81 | bool recursive, bool syntheticEvents, |
82 | WatcherInotify* parent, bool fromInternalEvent ) { | ||
73 | std::string dir( directory ); | 83 | std::string dir( directory ); |
74 | 84 | ||
75 | FileSystem::dirAddSlashAtEnd( dir ); | 85 | FileSystem::dirAddSlashAtEnd( dir ); |
@@ -133,6 +143,7 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
133 | { | 143 | { |
134 | Lock lock( mWatchesLock ); | 144 | Lock lock( mWatchesLock ); |
135 | mWatches.insert( std::make_pair( wd, pWatch ) ); | 145 | mWatches.insert( std::make_pair( wd, pWatch ) ); |
146 | mWatchesRef[pWatch->Directory] = wd; | ||
136 | } | 147 | } |
137 | 148 | ||
138 | if ( NULL == pWatch->Parent ) { | 149 | if ( NULL == pWatch->Parent ) { |
@@ -151,7 +162,17 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
151 | const FileInfo& cfi = it->second; | 162 | const FileInfo& cfi = it->second; |
152 | 163 | ||
153 | if ( cfi.isDirectory() && cfi.isReadable() ) { | 164 | if ( cfi.isDirectory() && cfi.isReadable() ) { |
154 | addWatch( cfi.Filepath, watcher, recursive, pWatch ); | 165 | addWatch( cfi.Filepath, watcher, recursive, syntheticEvents, pWatch ); |
166 | } | ||
167 | } | ||
168 | |||
169 | if ( fromInternalEvent && parent != NULL && syntheticEvents ) { | ||
170 | for ( const auto& file : files ) { | ||
171 | if ( file.second.isRegularFile() ) { | ||
172 | pWatch->Listener->handleFileAction( | ||
173 | pWatch->ID, pWatch->Directory, | ||
174 | FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add ); | ||
175 | } | ||
155 | } | 176 | } |
156 | } | 177 | } |
157 | } | 178 | } |
@@ -161,6 +182,8 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
161 | 182 | ||
162 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | 183 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { |
163 | WatchMap::iterator iter = mWatches.find( watchid ); | 184 | WatchMap::iterator iter = mWatches.find( watchid ); |
185 | if ( iter == mWatches.end() ) | ||
186 | return; | ||
164 | 187 | ||
165 | WatcherInotify* watch = iter->second; | 188 | WatcherInotify* watch = iter->second; |
166 | 189 | ||
@@ -173,22 +196,21 @@ void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | |||
173 | } | 196 | } |
174 | } | 197 | } |
175 | 198 | ||
176 | if ( watch->Recursive ) { | 199 | if ( watch->Recursive && NULL == watch->Parent ) { |
177 | WatchMap::iterator it = mWatches.begin(); | 200 | WatchMap::iterator it = mWatches.begin(); |
178 | std::list<WatchID> eraseWatches; | 201 | std::vector<WatchID> eraseWatches; |
179 | 202 | ||
180 | for ( ; it != mWatches.end(); ++it ) { | 203 | for ( ; it != mWatches.end(); ++it ) |
181 | if ( it->second != watch && it->second->inParentTree( watch ) ) { | 204 | if ( it->second != watch && it->second->inParentTree( watch ) ) |
182 | eraseWatches.push_back( it->second->InotifyID ); | 205 | eraseWatches.push_back( it->second->InotifyID ); |
183 | } | ||
184 | } | ||
185 | 206 | ||
186 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); | 207 | for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); |
187 | ++eit ) { | 208 | ++eit ) { |
188 | removeWatch( *eit ); | 209 | removeWatch( *eit ); |
189 | } | 210 | } |
190 | } | 211 | } |
191 | 212 | ||
213 | mWatchesRef.erase( watch->Directory ); | ||
192 | mWatches.erase( iter ); | 214 | mWatches.erase( iter ); |
193 | 215 | ||
194 | if ( NULL == watch->Parent ) { | 216 | if ( NULL == watch->Parent ) { |
@@ -217,52 +239,11 @@ void FileWatcherInotify::removeWatch( const std::string& directory ) { | |||
217 | Lock lock( mWatchesLock ); | 239 | Lock lock( mWatchesLock ); |
218 | Lock l( mRealWatchesLock ); | 240 | Lock l( mRealWatchesLock ); |
219 | 241 | ||
220 | WatchMap::iterator iter = mWatches.begin(); | 242 | std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory ); |
221 | 243 | if ( ref == mWatchesRef.end() ) | |
222 | for ( ; iter != mWatches.end(); ++iter ) { | 244 | return; |
223 | if ( directory == iter->second->Directory ) { | ||
224 | WatcherInotify* watch = iter->second; | ||
225 | |||
226 | if ( watch->Recursive ) { | ||
227 | WatchMap::iterator it = mWatches.begin(); | ||
228 | std::list<WatchID> eraseWatches; | ||
229 | |||
230 | for ( ; it != mWatches.end(); ++it ) { | ||
231 | if ( it->second->inParentTree( watch ) ) { | ||
232 | eraseWatches.push_back( it->second->InotifyID ); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); | ||
237 | eit != eraseWatches.end(); ++eit ) { | ||
238 | removeWatchLocked( *eit ); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | mWatches.erase( iter ); | ||
243 | |||
244 | if ( NULL == watch->Parent ) { | ||
245 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
246 | |||
247 | if ( eraseit != mRealWatches.end() ) { | ||
248 | mRealWatches.erase( eraseit ); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | int err = inotify_rm_watch( mFD, watch->InotifyID ); | ||
253 | |||
254 | if ( err < 0 ) { | ||
255 | efDEBUG( "Error removing watch %d: %s\n", watch->InotifyID, strerror( errno ) ); | ||
256 | } else { | ||
257 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), | ||
258 | watch->InotifyID ); | ||
259 | } | ||
260 | |||
261 | efSAFE_DELETE( watch ); | ||
262 | 245 | ||
263 | break; | 246 | removeWatchLocked( ref->second ); |
264 | } | ||
265 | } | ||
266 | } | 247 | } |
267 | 248 | ||
268 | void FileWatcherInotify::removeWatch( WatchID watchid ) { | 249 | void FileWatcherInotify::removeWatch( WatchID watchid ) { |
@@ -270,13 +251,6 @@ void FileWatcherInotify::removeWatch( WatchID watchid ) { | |||
270 | return; | 251 | return; |
271 | Lock initLock( mInitLock ); | 252 | Lock initLock( mInitLock ); |
272 | Lock lock( mWatchesLock ); | 253 | Lock lock( mWatchesLock ); |
273 | |||
274 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
275 | |||
276 | if ( iter == mWatches.end() ) { | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | removeWatchLocked( watchid ); | 254 | removeWatchLocked( watchid ); |
281 | } | 255 | } |
282 | 256 | ||
@@ -295,10 +269,8 @@ Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { | |||
295 | 269 | ||
296 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 270 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
297 | Watcher* watcher = it->second; | 271 | Watcher* watcher = it->second; |
298 | 272 | if ( watcher->Directory == watcherPath ) | |
299 | if ( watcher->Directory == watcherPath ) { | ||
300 | return watcher; | 273 | return watcher; |
301 | } | ||
302 | } | 274 | } |
303 | 275 | ||
304 | return NULL; | 276 | return NULL; |
@@ -422,7 +394,7 @@ void FileWatcherInotify::run() { | |||
422 | const std::string& oldFileName = ( *it ).second; | 394 | const std::string& oldFileName = ( *it ).second; |
423 | 395 | ||
424 | /// Check if the file move was a folder already being watched | 396 | /// Check if the file move was a folder already being watched |
425 | std::list<Watcher*> eraseWatches; | 397 | std::vector<Watcher*> eraseWatches; |
426 | 398 | ||
427 | { | 399 | { |
428 | Lock lock( mWatchesLock ); | 400 | Lock lock( mWatchesLock ); |
@@ -439,12 +411,15 @@ void FileWatcherInotify::run() { | |||
439 | } | 411 | } |
440 | 412 | ||
441 | /// Remove invalid watches | 413 | /// Remove invalid watches |
442 | eraseWatches.sort(); | 414 | std::stable_sort( eraseWatches.begin(), eraseWatches.end(), |
415 | []( const Watcher* left, const Watcher* right ) { | ||
416 | return left->Directory < right->Directory; | ||
417 | } ); | ||
443 | 418 | ||
444 | if ( eraseWatches.empty() ) { | 419 | if ( eraseWatches.empty() ) { |
445 | handleAction( watch, oldFileName, IN_DELETE ); | 420 | handleAction( watch, oldFileName, IN_DELETE ); |
446 | } else { | 421 | } else { |
447 | for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); | 422 | for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); |
448 | eit != eraseWatches.rend(); ++eit ) { | 423 | eit != eraseWatches.rend(); ++eit ) { |
449 | Watcher* rmWatch = *eit; | 424 | Watcher* rmWatch = *eit; |
450 | 425 | ||
@@ -485,8 +460,9 @@ void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) | |||
485 | } | 460 | } |
486 | 461 | ||
487 | if ( !found ) { | 462 | if ( !found ) { |
488 | addWatch( fpath, watch->Listener, watch->Recursive, | 463 | WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch ); |
489 | static_cast<WatcherInotify*>( watch ) ); | 464 | addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents, |
465 | static_cast<WatcherInotify*>( watch ), true ); | ||
490 | } | 466 | } |
491 | } | 467 | } |
492 | } | 468 | } |
@@ -496,7 +472,7 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena | |||
496 | if ( !watch || !watch->Listener || !mInitOK ) { | 472 | if ( !watch || !watch->Listener || !mInitOK ) { |
497 | return; | 473 | return; |
498 | } | 474 | } |
499 | 475 | mIsTakingAction = true; | |
500 | Lock initLock( mInitLock ); | 476 | Lock initLock( mInitLock ); |
501 | 477 | ||
502 | std::string fpath( watch->Directory + filename ); | 478 | std::string fpath( watch->Directory + filename ); |
@@ -563,18 +539,20 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena | |||
563 | } | 539 | } |
564 | } | 540 | } |
565 | } | 541 | } |
542 | mIsTakingAction = false; | ||
566 | } | 543 | } |
567 | 544 | ||
568 | std::list<std::string> FileWatcherInotify::directories() { | 545 | std::vector<std::string> FileWatcherInotify::directories() { |
569 | std::list<std::string> dirs; | 546 | std::vector<std::string> dirs; |
570 | 547 | ||
571 | Lock l( mRealWatchesLock ); | 548 | Lock l( mRealWatchesLock ); |
572 | 549 | ||
550 | dirs.reserve( mRealWatches.size() ); | ||
551 | |||
573 | WatchMap::iterator it = mRealWatches.begin(); | 552 | WatchMap::iterator it = mRealWatches.begin(); |
574 | 553 | ||
575 | for ( ; it != mRealWatches.end(); ++it ) { | 554 | for ( ; it != mRealWatches.end(); ++it ) |
576 | dirs.push_back( it->second->Directory ); | 555 | dirs.push_back( it->second->Directory ); |
577 | } | ||
578 | 556 | ||
579 | return dirs; | 557 | return dirs; |
580 | } | 558 | } |
@@ -585,11 +563,9 @@ bool FileWatcherInotify::pathInWatches( const std::string& path ) { | |||
585 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir | 563 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir |
586 | WatchMap::iterator it = mRealWatches.begin(); | 564 | WatchMap::iterator it = mRealWatches.begin(); |
587 | 565 | ||
588 | for ( ; it != mRealWatches.end(); ++it ) { | 566 | for ( ; it != mRealWatches.end(); ++it ) |
589 | if ( it->second->Directory == path ) { | 567 | if ( it->second->Directory == path ) |
590 | return true; | 568 | return true; |
591 | } | ||
592 | } | ||
593 | 569 | ||
594 | return false; | 570 | return false; |
595 | } | 571 | } |
diff --git a/src/3rdParty/efsw/FileWatcherInotify.hpp b/src/3rdParty/efsw/FileWatcherInotify.hpp index dc922ac..26d2c0b 100755..100644 --- a/src/3rdParty/efsw/FileWatcherInotify.hpp +++ b/src/3rdParty/efsw/FileWatcherInotify.hpp | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <efsw/WatcherInotify.hpp> | 8 | #include <efsw/WatcherInotify.hpp> |
9 | #include <map> | 9 | #include <map> |
10 | #include <unordered_map> | ||
10 | #include <vector> | 11 | #include <vector> |
11 | 12 | ||
12 | namespace efsw { | 13 | namespace efsw { |
@@ -24,23 +25,24 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
24 | 25 | ||
25 | /// Add a directory watch | 26 | /// Add a directory watch |
26 | /// On error returns WatchID with Error type. | 27 | /// On error returns WatchID with Error type. |
27 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
29 | const std::vector<WatcherOption>& options ) override; | ||
28 | 30 | ||
29 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 31 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
30 | void removeWatch( const std::string& directory ); | 32 | void removeWatch( const std::string& directory ) override; |
31 | 33 | ||
32 | /// Remove a directory watch. This is a map lookup O(logn). | 34 | /// Remove a directory watch. This is a map lookup O(logn). |
33 | void removeWatch( WatchID watchid ); | 35 | void removeWatch( WatchID watchid ) override; |
34 | 36 | ||
35 | /// Updates the watcher. Must be called often. | 37 | /// Updates the watcher. Must be called often. |
36 | void watch(); | 38 | void watch() override; |
37 | 39 | ||
38 | /// Handles the action | 40 | /// Handles the action |
39 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 41 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
40 | std::string oldFilename = "" ); | 42 | std::string oldFilename = "" ) override; |
41 | 43 | ||
42 | /// @return Returns a list of the directories that are being watched | 44 | /// @return Returns a list of the directories that are being watched |
43 | std::list<std::string> directories(); | 45 | std::vector<std::string> directories() override; |
44 | 46 | ||
45 | protected: | 47 | protected: |
46 | /// Map of WatchID to WatchStruct pointers | 48 | /// Map of WatchID to WatchStruct pointers |
@@ -49,6 +51,8 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
49 | /// User added watches | 51 | /// User added watches |
50 | WatchMap mRealWatches; | 52 | WatchMap mRealWatches; |
51 | 53 | ||
54 | std::unordered_map<std::string, WatchID> mWatchesRef; | ||
55 | |||
52 | /// inotify file descriptor | 56 | /// inotify file descriptor |
53 | int mFD; | 57 | int mFD; |
54 | 58 | ||
@@ -57,12 +61,14 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
57 | Mutex mWatchesLock; | 61 | Mutex mWatchesLock; |
58 | Mutex mRealWatchesLock; | 62 | Mutex mRealWatchesLock; |
59 | Mutex mInitLock; | 63 | Mutex mInitLock; |
64 | bool mIsTakingAction; | ||
60 | std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; | 65 | std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; |
61 | 66 | ||
62 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | 67 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
63 | WatcherInotify* parent = NULL ); | 68 | bool syntheticEvents, WatcherInotify* parent = NULL, |
69 | bool fromInternalEvent = false ); | ||
64 | 70 | ||
65 | bool pathInWatches( const std::string& path ); | 71 | bool pathInWatches( const std::string& path ) override; |
66 | 72 | ||
67 | private: | 73 | private: |
68 | void run(); | 74 | void run(); |
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.cpp b/src/3rdParty/efsw/FileWatcherKqueue.cpp index 38ffad9..ad03036 100755..100644 --- a/src/3rdParty/efsw/FileWatcherKqueue.cpp +++ b/src/3rdParty/efsw/FileWatcherKqueue.cpp | |||
@@ -45,7 +45,7 @@ FileWatcherKqueue::~FileWatcherKqueue() { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | 47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, |
48 | bool recursive ) { | 48 | bool recursive, const std::vector<WatcherOption>& /*options*/ ) { |
49 | static bool s_ug = false; | 49 | static bool s_ug = false; |
50 | 50 | ||
51 | std::string dir( directory ); | 51 | std::string dir( directory ); |
@@ -184,11 +184,13 @@ void FileWatcherKqueue::run() { | |||
184 | void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, | 184 | void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, |
185 | unsigned long /*action*/, std::string /*oldFilename*/ ) {} | 185 | unsigned long /*action*/, std::string /*oldFilename*/ ) {} |
186 | 186 | ||
187 | std::list<std::string> FileWatcherKqueue::directories() { | 187 | std::vector<std::string> FileWatcherKqueue::directories() { |
188 | std::list<std::string> dirs; | 188 | std::vector<std::string> dirs; |
189 | 189 | ||
190 | Lock lock( mWatchesLock ); | 190 | Lock lock( mWatchesLock ); |
191 | 191 | ||
192 | dirs.reserve( mWatches.size() ); | ||
193 | |||
192 | WatchMap::iterator it = mWatches.begin(); | 194 | WatchMap::iterator it = mWatches.begin(); |
193 | 195 | ||
194 | for ( ; it != mWatches.end(); ++it ) { | 196 | for ( ; it != mWatches.end(); ++it ) { |
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.hpp b/src/3rdParty/efsw/FileWatcherKqueue.hpp index 1bf3755..ff5327b 100755..100644 --- a/src/3rdParty/efsw/FileWatcherKqueue.hpp +++ b/src/3rdParty/efsw/FileWatcherKqueue.hpp | |||
@@ -21,23 +21,24 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
21 | 21 | ||
22 | /// Add a directory watch | 22 | /// Add a directory watch |
23 | /// On error returns WatchID with Error type. | 23 | /// On error returns WatchID with Error type. |
24 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 24 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
25 | const std::vector<WatcherOption> &options ) override; | ||
25 | 26 | ||
26 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
27 | void removeWatch( const std::string& directory ); | 28 | void removeWatch( const std::string& directory ) override; |
28 | 29 | ||
29 | /// Remove a directory watch. This is a map lookup O(logn). | 30 | /// Remove a directory watch. This is a map lookup O(logn). |
30 | void removeWatch( WatchID watchid ); | 31 | void removeWatch( WatchID watchid ) override; |
31 | 32 | ||
32 | /// Updates the watcher. Must be called often. | 33 | /// Updates the watcher. Must be called often. |
33 | void watch(); | 34 | void watch() override; |
34 | 35 | ||
35 | /// Handles the action | 36 | /// Handles the action |
36 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 37 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
37 | std::string oldFilename = "" ); | 38 | std::string oldFilename = "" ) override; |
38 | 39 | ||
39 | /// @return Returns a list of the directories that are being watched | 40 | /// @return Returns a list of the directories that are being watched |
40 | std::list<std::string> directories(); | 41 | std::vector<std::string> directories() override; |
41 | 42 | ||
42 | protected: | 43 | protected: |
43 | /// Map of WatchID to WatchStruct pointers | 44 | /// Map of WatchID to WatchStruct pointers |
@@ -53,7 +54,7 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
53 | 54 | ||
54 | Mutex mWatchesLock; | 55 | Mutex mWatchesLock; |
55 | 56 | ||
56 | std::list<WatchID> mRemoveList; | 57 | std::vector<WatchID> mRemoveList; |
57 | 58 | ||
58 | long mFileDescriptorCount; | 59 | long mFileDescriptorCount; |
59 | 60 | ||
@@ -61,7 +62,7 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
61 | 62 | ||
62 | bool isAddingWatcher() const; | 63 | bool isAddingWatcher() const; |
63 | 64 | ||
64 | bool pathInWatches( const std::string& path ); | 65 | bool pathInWatches( const std::string& path ) override; |
65 | 66 | ||
66 | void addFD(); | 67 | void addFD(); |
67 | 68 | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.cpp b/src/3rdParty/efsw/FileWatcherWin32.cpp index 963dc98..19b71d7 100755..100644 --- a/src/3rdParty/efsw/FileWatcherWin32.cpp +++ b/src/3rdParty/efsw/FileWatcherWin32.cpp | |||
@@ -1,257 +1,267 @@ | |||
1 | #include <efsw/FileSystem.hpp> | 1 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/FileWatcherWin32.hpp> | 2 | #include <efsw/FileWatcherWin32.hpp> |
3 | #include <efsw/Lock.hpp> | 3 | #include <efsw/Lock.hpp> |
4 | #include <efsw/String.hpp> | 4 | #include <efsw/String.hpp> |
5 | #include <efsw/System.hpp> | 5 | #include <efsw/System.hpp> |
6 | 6 | ||
7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
8 | 8 | ||
9 | namespace efsw { | 9 | namespace efsw { |
10 | 10 | ||
11 | FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : | 11 | FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : |
12 | FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { | 12 | FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { |
13 | mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); | 13 | mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); |
14 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) | 14 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) |
15 | mInitOK = true; | 15 | mInitOK = true; |
16 | } | 16 | } |
17 | 17 | ||
18 | FileWatcherWin32::~FileWatcherWin32() { | 18 | FileWatcherWin32::~FileWatcherWin32() { |
19 | mInitOK = false; | 19 | mInitOK = false; |
20 | 20 | ||
21 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { | 21 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { |
22 | PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); | 22 | PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); |
23 | } | 23 | } |
24 | 24 | ||
25 | efSAFE_DELETE( mThread ); | 25 | efSAFE_DELETE( mThread ); |
26 | 26 | ||
27 | removeAllWatches(); | 27 | removeAllWatches(); |
28 | 28 | ||
29 | CloseHandle( mIOCP ); | 29 | if ( mIOCP ) |
30 | } | 30 | CloseHandle( mIOCP ); |
31 | 31 | } | |
32 | WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, | 32 | |
33 | bool recursive ) { | 33 | WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, |
34 | std::string dir( directory ); | 34 | bool recursive, const std::vector<WatcherOption> &options ) { |
35 | 35 | std::string dir( directory ); | |
36 | FileInfo fi( dir ); | 36 | |
37 | 37 | FileInfo fi( dir ); | |
38 | if ( !fi.isDirectory() ) { | 38 | |
39 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | 39 | if ( !fi.isDirectory() ) { |
40 | } else if ( !fi.isReadable() ) { | 40 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); |
41 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | 41 | } else if ( !fi.isReadable() ) { |
42 | } | 42 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); |
43 | 43 | } | |
44 | FileSystem::dirAddSlashAtEnd( dir ); | 44 | |
45 | 45 | FileSystem::dirAddSlashAtEnd( dir ); | |
46 | Lock lock( mWatchesLock ); | 46 | |
47 | 47 | Lock lock( mWatchesLock ); | |
48 | if ( pathInWatches( dir ) ) { | 48 | |
49 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); | 49 | if ( pathInWatches( dir ) ) { |
50 | } | 50 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); |
51 | 51 | } | |
52 | WatchID watchid = ++mLastWatchID; | 52 | |
53 | 53 | WatchID watchid = ++mLastWatchID; | |
54 | WatcherStructWin32* watch = CreateWatch( | 54 | |
55 | String::fromUtf8( dir ).toWideString().c_str(), recursive, | 55 | DWORD bufferSize = static_cast<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); |
56 | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME | | 56 | DWORD notifyFilter = static_cast<DWORD>( getOptionValue(options, Option::WinNotifyFilter, |
57 | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, | 57 | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | |
58 | mIOCP ); | 58 | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | |
59 | 59 | FILE_NOTIFY_CHANGE_SIZE) ); | |
60 | if ( NULL == watch ) { | 60 | |
61 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | 61 | WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), |
62 | } | 62 | recursive, bufferSize, notifyFilter, mIOCP ); |
63 | 63 | ||
64 | // Add the handle to the handles vector | 64 | if ( NULL == watch ) { |
65 | watch->Watch->ID = watchid; | 65 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); |
66 | watch->Watch->Watch = this; | 66 | } |
67 | watch->Watch->Listener = watcher; | 67 | |
68 | watch->Watch->DirName = new char[dir.length() + 1]; | 68 | // Add the handle to the handles vector |
69 | strcpy( watch->Watch->DirName, dir.c_str() ); | 69 | watch->Watch->ID = watchid; |
70 | 70 | watch->Watch->Watch = this; | |
71 | mWatches.insert( watch ); | 71 | watch->Watch->Listener = watcher; |
72 | 72 | watch->Watch->DirName = new char[dir.length() + 1]; | |
73 | return watchid; | 73 | strcpy( watch->Watch->DirName, dir.c_str() ); |
74 | } | 74 | |
75 | 75 | mWatches.insert( watch ); | |
76 | void FileWatcherWin32::removeWatch( const std::string& directory ) { | 76 | |
77 | Lock lock( mWatchesLock ); | 77 | return watchid; |
78 | 78 | } | |
79 | Watches::iterator iter = mWatches.begin(); | 79 | |
80 | 80 | void FileWatcherWin32::removeWatch( const std::string& directory ) { | |
81 | for ( ; iter != mWatches.end(); ++iter ) { | 81 | Lock lock( mWatchesLock ); |
82 | if ( directory == ( *iter )->Watch->DirName ) { | 82 | |
83 | removeWatch( *iter ); | 83 | Watches::iterator iter = mWatches.begin(); |
84 | break; | 84 | |
85 | } | 85 | for ( ; iter != mWatches.end(); ++iter ) { |
86 | } | 86 | if ( directory == ( *iter )->Watch->DirName ) { |
87 | } | 87 | removeWatch( *iter ); |
88 | 88 | break; | |
89 | void FileWatcherWin32::removeWatch( WatchID watchid ) { | 89 | } |
90 | Lock lock( mWatchesLock ); | 90 | } |
91 | 91 | } | |
92 | Watches::iterator iter = mWatches.begin(); | 92 | |
93 | 93 | void FileWatcherWin32::removeWatch( WatchID watchid ) { | |
94 | for ( ; iter != mWatches.end(); ++iter ) { | 94 | Lock lock( mWatchesLock ); |
95 | // Find the watch ID | 95 | |
96 | if ( ( *iter )->Watch->ID == watchid ) { | 96 | Watches::iterator iter = mWatches.begin(); |
97 | removeWatch( *iter ); | 97 | |
98 | return; | 98 | for ( ; iter != mWatches.end(); ++iter ) { |
99 | } | 99 | // Find the watch ID |
100 | } | 100 | if ( ( *iter )->Watch->ID == watchid ) { |
101 | } | 101 | removeWatch( *iter ); |
102 | 102 | return; | |
103 | void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { | 103 | } |
104 | Lock lock( mWatchesLock ); | 104 | } |
105 | 105 | } | |
106 | DestroyWatch( watch ); | 106 | |
107 | mWatches.erase( watch ); | 107 | void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { |
108 | } | 108 | Lock lock( mWatchesLock ); |
109 | 109 | ||
110 | void FileWatcherWin32::watch() { | 110 | DestroyWatch( watch ); |
111 | if ( NULL == mThread ) { | 111 | mWatches.erase( watch ); |
112 | mThread = new Thread( &FileWatcherWin32::run, this ); | 112 | } |
113 | mThread->launch(); | 113 | |
114 | } | 114 | void FileWatcherWin32::watch() { |
115 | } | 115 | if ( NULL == mThread ) { |
116 | 116 | mThread = new Thread( &FileWatcherWin32::run, this ); | |
117 | void FileWatcherWin32::removeAllWatches() { | 117 | mThread->launch(); |
118 | Lock lock( mWatchesLock ); | 118 | } |
119 | 119 | } | |
120 | Watches::iterator iter = mWatches.begin(); | 120 | |
121 | 121 | void FileWatcherWin32::removeAllWatches() { | |
122 | for ( ; iter != mWatches.end(); ++iter ) { | 122 | Lock lock( mWatchesLock ); |
123 | DestroyWatch( ( *iter ) ); | 123 | |
124 | } | 124 | Watches::iterator iter = mWatches.begin(); |
125 | 125 | ||
126 | mWatches.clear(); | 126 | for ( ; iter != mWatches.end(); ++iter ) { |
127 | } | 127 | DestroyWatch( ( *iter ) ); |
128 | 128 | } | |
129 | void FileWatcherWin32::run() { | 129 | |
130 | do { | 130 | mWatches.clear(); |
131 | if ( mInitOK && !mWatches.empty() ) { | 131 | } |
132 | DWORD numOfBytes = 0; | 132 | |
133 | OVERLAPPED* ov = NULL; | 133 | void FileWatcherWin32::run() { |
134 | ULONG_PTR compKey = 0; | 134 | do { |
135 | BOOL res = FALSE; | 135 | if ( mInitOK && !mWatches.empty() ) { |
136 | 136 | DWORD numOfBytes = 0; | |
137 | while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, | 137 | OVERLAPPED* ov = NULL; |
138 | INFINITE ) ) != FALSE ) { | 138 | ULONG_PTR compKey = 0; |
139 | if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { | 139 | BOOL res = FALSE; |
140 | break; | 140 | |
141 | } else { | 141 | while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, |
142 | Lock lock( mWatchesLock ); | 142 | INFINITE ) ) != FALSE ) { |
143 | WatchCallback( numOfBytes, ov ); | 143 | if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { |
144 | } | 144 | break; |
145 | } | 145 | } else { |
146 | } else { | 146 | Lock lock( mWatchesLock ); |
147 | System::sleep( 10 ); | 147 | if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end()) |
148 | } | 148 | WatchCallback( numOfBytes, ov ); |
149 | } while ( mInitOK ); | 149 | } |
150 | 150 | } | |
151 | removeAllWatches(); | 151 | } else { |
152 | } | 152 | System::sleep( 10 ); |
153 | 153 | } | |
154 | void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, | 154 | } while ( mInitOK ); |
155 | unsigned long action, std::string /*oldFilename*/ ) { | 155 | |
156 | Action fwAction; | 156 | removeAllWatches(); |
157 | 157 | } | |
158 | switch ( action ) { | 158 | |
159 | case FILE_ACTION_RENAMED_OLD_NAME: | 159 | void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, |
160 | watch->OldFileName = filename; | 160 | unsigned long action, std::string /*oldFilename*/ ) { |
161 | return; | 161 | Action fwAction; |
162 | case FILE_ACTION_ADDED: | 162 | |
163 | fwAction = Actions::Add; | 163 | switch ( action ) { |
164 | break; | 164 | case FILE_ACTION_RENAMED_OLD_NAME: |
165 | case FILE_ACTION_RENAMED_NEW_NAME: { | 165 | watch->OldFileName = filename; |
166 | fwAction = Actions::Moved; | 166 | return; |
167 | 167 | case FILE_ACTION_ADDED: | |
168 | std::string fpath( watch->Directory + filename ); | 168 | fwAction = Actions::Add; |
169 | 169 | break; | |
170 | // Update the directory path | 170 | case FILE_ACTION_RENAMED_NEW_NAME: { |
171 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | 171 | fwAction = Actions::Moved; |
172 | // Update the new directory path | 172 | |
173 | std::string opath( watch->Directory + watch->OldFileName ); | 173 | std::string fpath( watch->Directory + filename ); |
174 | FileSystem::dirAddSlashAtEnd( opath ); | 174 | |
175 | FileSystem::dirAddSlashAtEnd( fpath ); | 175 | // Update the directory path |
176 | 176 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | |
177 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 177 | // Update the new directory path |
178 | if ( ( *it )->Watch->Directory == opath ) { | 178 | std::string opath( watch->Directory + watch->OldFileName ); |
179 | ( *it )->Watch->Directory = fpath; | 179 | FileSystem::dirAddSlashAtEnd( opath ); |
180 | 180 | FileSystem::dirAddSlashAtEnd( fpath ); | |
181 | break; | 181 | |
182 | } | 182 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
183 | } | 183 | if ( ( *it )->Watch->Directory == opath ) { |
184 | } | 184 | ( *it )->Watch->Directory = fpath; |
185 | 185 | ||
186 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | 186 | break; |
187 | std::string realFilename = filename; | 187 | } |
188 | std::size_t sepPos = filename.find_last_of( "/\\" ); | 188 | } |
189 | std::string oldFolderPath = | 189 | } |
190 | static_cast<WatcherWin32*>( watch )->DirName + | 190 | |
191 | watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); | 191 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); |
192 | 192 | std::string realFilename = filename; | |
193 | if ( sepPos != std::string::npos ) { | 193 | std::size_t sepPos = filename.find_last_of( "/\\" ); |
194 | folderPath += filename.substr( 0, sepPos ); | 194 | std::string oldFolderPath = |
195 | realFilename = filename.substr( sepPos + 1 ); | 195 | static_cast<WatcherWin32*>( watch )->DirName + |
196 | } | 196 | watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); |
197 | 197 | ||
198 | if ( folderPath == oldFolderPath ) { | 198 | if ( sepPos != std::string::npos ) { |
199 | watch->Listener->handleFileAction( | 199 | folderPath += |
200 | watch->ID, folderPath, realFilename, fwAction, | 200 | filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); |
201 | FileSystem::fileNameFromPath( watch->OldFileName ) ); | 201 | realFilename = filename.substr( sepPos + 1 ); |
202 | } else { | 202 | } |
203 | watch->Listener->handleFileAction( watch->ID, | 203 | |
204 | static_cast<WatcherWin32*>( watch )->DirName, | 204 | if ( folderPath == oldFolderPath ) { |
205 | filename, fwAction, watch->OldFileName ); | 205 | watch->Listener->handleFileAction( |
206 | } | 206 | watch->ID, folderPath, realFilename, fwAction, |
207 | return; | 207 | FileSystem::fileNameFromPath( watch->OldFileName ) ); |
208 | } | 208 | } else { |
209 | case FILE_ACTION_REMOVED: | 209 | watch->Listener->handleFileAction( watch->ID, |
210 | fwAction = Actions::Delete; | 210 | static_cast<WatcherWin32*>( watch )->DirName, |
211 | break; | 211 | filename, fwAction, watch->OldFileName ); |
212 | case FILE_ACTION_MODIFIED: | 212 | } |
213 | fwAction = Actions::Modified; | 213 | return; |
214 | break; | 214 | } |
215 | default: | 215 | case FILE_ACTION_REMOVED: |
216 | return; | 216 | fwAction = Actions::Delete; |
217 | }; | 217 | break; |
218 | 218 | case FILE_ACTION_MODIFIED: | |
219 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | 219 | fwAction = Actions::Modified; |
220 | std::string realFilename = filename; | 220 | break; |
221 | std::size_t sepPos = filename.find_last_of( "/\\" ); | 221 | default: |
222 | 222 | return; | |
223 | if ( sepPos != std::string::npos ) { | 223 | }; |
224 | folderPath += filename.substr( 0, sepPos ); | 224 | |
225 | realFilename = filename.substr( sepPos + 1 ); | 225 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); |
226 | } | 226 | std::string realFilename = filename; |
227 | 227 | std::size_t sepPos = filename.find_last_of( "/\\" ); | |
228 | watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); | 228 | |
229 | } | 229 | if ( sepPos != std::string::npos ) { |
230 | 230 | folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); | |
231 | std::list<std::string> FileWatcherWin32::directories() { | 231 | realFilename = filename.substr( sepPos + 1 ); |
232 | std::list<std::string> dirs; | 232 | } |
233 | 233 | ||
234 | Lock lock( mWatchesLock ); | 234 | FileSystem::dirAddSlashAtEnd( folderPath ); |
235 | 235 | ||
236 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 236 | watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); |
237 | dirs.push_back( std::string( ( *it )->Watch->DirName ) ); | 237 | } |
238 | } | 238 | |
239 | 239 | std::vector<std::string> FileWatcherWin32::directories() { | |
240 | return dirs; | 240 | std::vector<std::string> dirs; |
241 | } | 241 | |
242 | 242 | Lock lock( mWatchesLock ); | |
243 | bool FileWatcherWin32::pathInWatches( const std::string& path ) { | 243 | |
244 | Lock lock( mWatchesLock ); | 244 | dirs.reserve( mWatches.size() ); |
245 | 245 | ||
246 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 246 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
247 | if ( ( *it )->Watch->DirName == path ) { | 247 | dirs.push_back( std::string( ( *it )->Watch->DirName ) ); |
248 | return true; | 248 | } |
249 | } | 249 | |
250 | } | 250 | return dirs; |
251 | 251 | } | |
252 | return false; | 252 | |
253 | } | 253 | bool FileWatcherWin32::pathInWatches( const std::string& path ) { |
254 | 254 | Lock lock( mWatchesLock ); | |
255 | } // namespace efsw | 255 | |
256 | 256 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | |
257 | #endif | 257 | if ( ( *it )->Watch->DirName == path ) { |
258 | return true; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | return false; | ||
263 | } | ||
264 | |||
265 | } // namespace efsw | ||
266 | |||
267 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.hpp b/src/3rdParty/efsw/FileWatcherWin32.hpp index 94439cf..3016aac 100755..100644 --- a/src/3rdParty/efsw/FileWatcherWin32.hpp +++ b/src/3rdParty/efsw/FileWatcherWin32.hpp | |||
@@ -1,70 +1,71 @@ | |||
1 | #ifndef EFSW_FILEWATCHERWIN32_HPP | 1 | #ifndef EFSW_FILEWATCHERWIN32_HPP |
2 | #define EFSW_FILEWATCHERWIN32_HPP | 2 | #define EFSW_FILEWATCHERWIN32_HPP |
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | 5 | ||
6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
7 | 7 | ||
8 | #include <efsw/WatcherWin32.hpp> | 8 | #include <efsw/WatcherWin32.hpp> |
9 | #include <map> | 9 | #include <map> |
10 | #include <set> | 10 | #include <unordered_set> |
11 | #include <vector> | 11 | #include <vector> |
12 | 12 | ||
13 | namespace efsw { | 13 | namespace efsw { |
14 | 14 | ||
15 | /// Implementation for Win32 based on ReadDirectoryChangesW. | 15 | /// Implementation for Win32 based on ReadDirectoryChangesW. |
16 | /// @class FileWatcherWin32 | 16 | /// @class FileWatcherWin32 |
17 | class FileWatcherWin32 : public FileWatcherImpl { | 17 | class FileWatcherWin32 : public FileWatcherImpl { |
18 | public: | 18 | public: |
19 | /// type for a map from WatchID to WatcherWin32 pointer | 19 | /// type for a map from WatchID to WatcherWin32 pointer |
20 | typedef std::set<WatcherStructWin32*> Watches; | 20 | typedef std::unordered_set<WatcherStructWin32*> Watches; |
21 | 21 | ||
22 | FileWatcherWin32( FileWatcher* parent ); | 22 | FileWatcherWin32( FileWatcher* parent ); |
23 | 23 | ||
24 | virtual ~FileWatcherWin32(); | 24 | virtual ~FileWatcherWin32(); |
25 | 25 | ||
26 | /// Add a directory watch | 26 | /// Add a directory watch |
27 | /// On error returns WatchID with Error type. | 27 | /// On error returns WatchID with Error type. |
28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
29 | 29 | const std::vector<WatcherOption> &options ) override; | |
30 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 30 | |
31 | void removeWatch( const std::string& directory ); | 31 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
32 | 32 | void removeWatch( const std::string& directory ) override; | |
33 | /// Remove a directory watch. This is a map lookup O(logn). | 33 | |
34 | void removeWatch( WatchID watchid ); | 34 | /// Remove a directory watch. This is a map lookup O(logn). |
35 | 35 | void removeWatch( WatchID watchid ) override; | |
36 | /// Updates the watcher. Must be called often. | 36 | |
37 | void watch(); | 37 | /// Updates the watcher. Must be called often. |
38 | 38 | void watch() override; | |
39 | /// Handles the action | 39 | |
40 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 40 | /// Handles the action |
41 | std::string oldFilename = "" ); | 41 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
42 | 42 | std::string oldFilename = "" ) override; | |
43 | /// @return Returns a list of the directories that are being watched | 43 | |
44 | std::list<std::string> directories(); | 44 | /// @return Returns a list of the directories that are being watched |
45 | 45 | std::vector<std::string> directories() override; | |
46 | protected: | 46 | |
47 | HANDLE mIOCP; | 47 | protected: |
48 | Watches mWatches; | 48 | HANDLE mIOCP; |
49 | 49 | Watches mWatches; | |
50 | /// The last watchid | 50 | |
51 | WatchID mLastWatchID; | 51 | /// The last watchid |
52 | Thread* mThread; | 52 | WatchID mLastWatchID; |
53 | Mutex mWatchesLock; | 53 | Thread* mThread; |
54 | 54 | Mutex mWatchesLock; | |
55 | bool pathInWatches( const std::string& path ); | 55 | |
56 | 56 | bool pathInWatches( const std::string& path ) override; | |
57 | /// Remove all directory watches. | 57 | |
58 | void removeAllWatches(); | 58 | /// Remove all directory watches. |
59 | 59 | void removeAllWatches(); | |
60 | void removeWatch( WatcherStructWin32* watch ); | 60 | |
61 | 61 | void removeWatch( WatcherStructWin32* watch ); | |
62 | private: | 62 | |
63 | void run(); | 63 | private: |
64 | }; | 64 | void run(); |
65 | 65 | }; | |
66 | } // namespace efsw | 66 | |
67 | 67 | } // namespace efsw | |
68 | #endif | 68 | |
69 | 69 | #endif | |
70 | #endif | 70 | |
71 | #endif | ||
diff --git a/src/3rdParty/efsw/LICENSE b/src/3rdParty/efsw/LICENSE index 37f354a..37f354a 100755..100644 --- a/src/3rdParty/efsw/LICENSE +++ b/src/3rdParty/efsw/LICENSE | |||
diff --git a/src/3rdParty/efsw/Lock.hpp b/src/3rdParty/efsw/Lock.hpp index e8c522a..e8c522a 100755..100644 --- a/src/3rdParty/efsw/Lock.hpp +++ b/src/3rdParty/efsw/Lock.hpp | |||
diff --git a/src/3rdParty/efsw/Log.cpp b/src/3rdParty/efsw/Log.cpp index ddf7a62..6f32df7 100755..100644 --- a/src/3rdParty/efsw/Log.cpp +++ b/src/3rdParty/efsw/Log.cpp | |||
@@ -1,20 +1,31 @@ | |||
1 | #include <efsw/efsw.hpp> | 1 | #include <efsw/efsw.hpp> |
2 | #include <efsw/Debug.hpp> | ||
2 | 3 | ||
3 | namespace efsw { namespace Errors { | 4 | namespace efsw { namespace Errors { |
4 | 5 | ||
5 | static std::string LastError; | 6 | static std::string LastError = ""; |
7 | static Error LastErrorCode = NoError; | ||
6 | 8 | ||
7 | std::string Log::getLastErrorLog() { | 9 | std::string Log::getLastErrorLog() { |
8 | return LastError; | 10 | return LastError; |
9 | } | 11 | } |
10 | 12 | ||
13 | Error Log::getLastErrorCode() { | ||
14 | return LastErrorCode; | ||
15 | } | ||
16 | |||
17 | void Log::clearLastError() { | ||
18 | LastErrorCode = NoError; | ||
19 | LastError = ""; | ||
20 | } | ||
21 | |||
11 | Error Log::createLastError( Error err, std::string log ) { | 22 | Error Log::createLastError( Error err, std::string log ) { |
12 | switch ( err ) { | 23 | switch ( err ) { |
13 | case FileNotFound: | 24 | case FileNotFound: |
14 | LastError = "File not found ( " + log + " )"; | 25 | LastError = "File not found ( " + log + " )"; |
15 | break; | 26 | break; |
16 | case FileRepeated: | 27 | case FileRepeated: |
17 | LastError = "File reapeated in watches ( " + log + " )"; | 28 | LastError = "File repeated in watches ( " + log + " )"; |
18 | break; | 29 | break; |
19 | case FileOutOfScope: | 30 | case FileOutOfScope: |
20 | LastError = "Symlink file out of scope ( " + log + " )"; | 31 | LastError = "Symlink file out of scope ( " + log + " )"; |
@@ -23,11 +34,15 @@ Error Log::createLastError( Error err, std::string log ) { | |||
23 | LastError = | 34 | LastError = |
24 | "File is located in a remote file system, use a generic watcher. ( " + log + " )"; | 35 | "File is located in a remote file system, use a generic watcher. ( " + log + " )"; |
25 | break; | 36 | break; |
37 | case WatcherFailed: | ||
38 | LastError = "File system watcher failed ( " + log + " )"; | ||
39 | break; | ||
26 | case Unspecified: | 40 | case Unspecified: |
27 | default: | 41 | default: |
28 | LastError = log; | 42 | LastError = log; |
29 | } | 43 | } |
30 | 44 | ||
45 | efDEBUG( "%s\n", LastError.c_str() ); | ||
31 | return err; | 46 | return err; |
32 | } | 47 | } |
33 | 48 | ||
diff --git a/src/3rdParty/efsw/Mutex.cpp b/src/3rdParty/efsw/Mutex.cpp index c961db1..c961db1 100755..100644 --- a/src/3rdParty/efsw/Mutex.cpp +++ b/src/3rdParty/efsw/Mutex.cpp | |||
diff --git a/src/3rdParty/efsw/Mutex.hpp b/src/3rdParty/efsw/Mutex.hpp index d98ad17..d98ad17 100755..100644 --- a/src/3rdParty/efsw/Mutex.hpp +++ b/src/3rdParty/efsw/Mutex.hpp | |||
diff --git a/src/3rdParty/efsw/String.cpp b/src/3rdParty/efsw/String.cpp index e3ba68f..e3ba68f 100755..100644 --- a/src/3rdParty/efsw/String.cpp +++ b/src/3rdParty/efsw/String.cpp | |||
diff --git a/src/3rdParty/efsw/String.hpp b/src/3rdParty/efsw/String.hpp index 65bce33..b42b945 100755..100644 --- a/src/3rdParty/efsw/String.hpp +++ b/src/3rdParty/efsw/String.hpp | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <cstdlib> | 11 | #include <cstdlib> |
12 | #include <cstring> | 12 | #include <cstring> |
13 | #include <efsw/base.hpp> | 13 | #include <efsw/base.hpp> |
14 | #include <fstream> | ||
15 | #include <iostream> | 14 | #include <iostream> |
16 | #include <locale> | 15 | #include <locale> |
17 | #include <sstream> | 16 | #include <sstream> |
@@ -24,7 +23,7 @@ namespace efsw { | |||
24 | * **/ | 23 | * **/ |
25 | class String { | 24 | class String { |
26 | public: | 25 | public: |
27 | typedef Uint32 StringBaseType; | 26 | typedef char32_t StringBaseType; |
28 | typedef std::basic_string<StringBaseType> StringType; | 27 | typedef std::basic_string<StringBaseType> StringType; |
29 | typedef StringType::iterator Iterator; //! Iterator type | 28 | typedef StringType::iterator Iterator; //! Iterator type |
30 | typedef StringType::const_iterator ConstIterator; //! Constant iterator type | 29 | typedef StringType::const_iterator ConstIterator; //! Constant iterator type |
diff --git a/src/3rdParty/efsw/System.cpp b/src/3rdParty/efsw/System.cpp index ba68bf4..ba68bf4 100755..100644 --- a/src/3rdParty/efsw/System.cpp +++ b/src/3rdParty/efsw/System.cpp | |||
diff --git a/src/3rdParty/efsw/System.hpp b/src/3rdParty/efsw/System.hpp index 498e121..498e121 100755..100644 --- a/src/3rdParty/efsw/System.hpp +++ b/src/3rdParty/efsw/System.hpp | |||
diff --git a/src/3rdParty/efsw/Thread.cpp b/src/3rdParty/efsw/Thread.cpp index e3f0fa0..cfa88b4 100755..100644 --- a/src/3rdParty/efsw/Thread.cpp +++ b/src/3rdParty/efsw/Thread.cpp | |||
@@ -34,7 +34,8 @@ void Thread::terminate() { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | void Thread::run() { | 36 | void Thread::run() { |
37 | mEntryPoint->run(); | 37 | if ( mEntryPoint ) |
38 | mEntryPoint->run(); | ||
38 | } | 39 | } |
39 | 40 | ||
40 | } // namespace efsw | 41 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/Thread.hpp b/src/3rdParty/efsw/Thread.hpp index b60373c..b60373c 100755..100644 --- a/src/3rdParty/efsw/Thread.hpp +++ b/src/3rdParty/efsw/Thread.hpp | |||
diff --git a/src/3rdParty/efsw/Utf.hpp b/src/3rdParty/efsw/Utf.hpp index 6e9ea71..1b042cd 100755..100644 --- a/src/3rdParty/efsw/Utf.hpp +++ b/src/3rdParty/efsw/Utf.hpp | |||
@@ -1,721 +1,721 @@ | |||
1 | /** NOTE: | 1 | /** NOTE: |
2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( | 2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( |
3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not | 3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not |
4 | *the original implementation from SFML2. | 4 | *the original implementation from SFML2. |
5 | * */ | 5 | * */ |
6 | 6 | ||
7 | #ifndef EFSW_UTF_HPP | 7 | #ifndef EFSW_UTF_HPP |
8 | #define EFSW_UTF_HPP | 8 | #define EFSW_UTF_HPP |
9 | 9 | ||
10 | //////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////// |
11 | // Headers | 11 | // Headers |
12 | //////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////// |
13 | #include <cstdlib> | 13 | #include <cstdlib> |
14 | #include <efsw/base.hpp> | 14 | #include <efsw/base.hpp> |
15 | #include <locale> | 15 | #include <locale> |
16 | #include <string> | 16 | #include <string> |
17 | 17 | ||
18 | namespace efsw { | 18 | namespace efsw { |
19 | 19 | ||
20 | template <unsigned int N> class Utf; | 20 | template <unsigned int N> class Utf; |
21 | 21 | ||
22 | //////////////////////////////////////////////////////////// | 22 | //////////////////////////////////////////////////////////// |
23 | /// \brief Specialization of the Utf template for UTF-8 | 23 | /// \brief Specialization of the Utf template for UTF-8 |
24 | /// | 24 | /// |
25 | //////////////////////////////////////////////////////////// | 25 | //////////////////////////////////////////////////////////// |
26 | template <> class Utf<8> { | 26 | template <> class Utf<8> { |
27 | public: | 27 | public: |
28 | //////////////////////////////////////////////////////////// | 28 | //////////////////////////////////////////////////////////// |
29 | /// \brief Decode a single UTF-8 character | 29 | /// \brief Decode a single UTF-8 character |
30 | /// | 30 | /// |
31 | /// Decoding a character means finding its unique 32-bits | 31 | /// Decoding a character means finding its unique 32-bits |
32 | /// code (called the codepoint) in the Unicode standard. | 32 | /// code (called the codepoint) in the Unicode standard. |
33 | /// | 33 | /// |
34 | /// \param begin Iterator pointing to the beginning of the input sequence | 34 | /// \param begin Iterator pointing to the beginning of the input sequence |
35 | /// \param end Iterator pointing to the end of the input sequence | 35 | /// \param end Iterator pointing to the end of the input sequence |
36 | /// \param output Codepoint of the decoded UTF-8 character | 36 | /// \param output Codepoint of the decoded UTF-8 character |
37 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 37 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
38 | /// | 38 | /// |
39 | /// \return Iterator pointing to one past the last read element of the input sequence | 39 | /// \return Iterator pointing to one past the last read element of the input sequence |
40 | /// | 40 | /// |
41 | //////////////////////////////////////////////////////////// | 41 | //////////////////////////////////////////////////////////// |
42 | template <typename In> | 42 | template <typename In> |
43 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 43 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
44 | 44 | ||
45 | //////////////////////////////////////////////////////////// | 45 | //////////////////////////////////////////////////////////// |
46 | /// \brief Encode a single UTF-8 character | 46 | /// \brief Encode a single UTF-8 character |
47 | /// | 47 | /// |
48 | /// Encoding a character means converting a unique 32-bits | 48 | /// Encoding a character means converting a unique 32-bits |
49 | /// code (called the codepoint) in the target encoding, UTF-8. | 49 | /// code (called the codepoint) in the target encoding, UTF-8. |
50 | /// | 50 | /// |
51 | /// \param input Codepoint to encode as UTF-8 | 51 | /// \param input Codepoint to encode as UTF-8 |
52 | /// \param output Iterator pointing to the beginning of the output sequence | 52 | /// \param output Iterator pointing to the beginning of the output sequence |
53 | /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) | 53 | /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) |
54 | /// | 54 | /// |
55 | /// \return Iterator to the end of the output sequence which has been written | 55 | /// \return Iterator to the end of the output sequence which has been written |
56 | /// | 56 | /// |
57 | //////////////////////////////////////////////////////////// | 57 | //////////////////////////////////////////////////////////// |
58 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); | 58 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); |
59 | 59 | ||
60 | //////////////////////////////////////////////////////////// | 60 | //////////////////////////////////////////////////////////// |
61 | /// \brief Advance to the next UTF-8 character | 61 | /// \brief Advance to the next UTF-8 character |
62 | /// | 62 | /// |
63 | /// This function is necessary for multi-elements encodings, as | 63 | /// This function is necessary for multi-elements encodings, as |
64 | /// a single character may use more than 1 storage element. | 64 | /// a single character may use more than 1 storage element. |
65 | /// | 65 | /// |
66 | /// \param begin Iterator pointing to the beginning of the input sequence | 66 | /// \param begin Iterator pointing to the beginning of the input sequence |
67 | /// \param end Iterator pointing to the end of the input sequence | 67 | /// \param end Iterator pointing to the end of the input sequence |
68 | /// | 68 | /// |
69 | /// \return Iterator pointing to one past the last read element of the input sequence | 69 | /// \return Iterator pointing to one past the last read element of the input sequence |
70 | /// | 70 | /// |
71 | //////////////////////////////////////////////////////////// | 71 | //////////////////////////////////////////////////////////// |
72 | template <typename In> static In Next( In begin, In end ); | 72 | template <typename In> static In Next( In begin, In end ); |
73 | 73 | ||
74 | //////////////////////////////////////////////////////////// | 74 | //////////////////////////////////////////////////////////// |
75 | /// \brief Count the number of characters of a UTF-8 sequence | 75 | /// \brief Count the number of characters of a UTF-8 sequence |
76 | /// | 76 | /// |
77 | /// This function is necessary for multi-elements encodings, as | 77 | /// This function is necessary for multi-elements encodings, as |
78 | /// a single character may use more than 1 storage element, thus the | 78 | /// a single character may use more than 1 storage element, thus the |
79 | /// total size can be different from (begin - end). | 79 | /// total size can be different from (begin - end). |
80 | /// | 80 | /// |
81 | /// \param begin Iterator pointing to the beginning of the input sequence | 81 | /// \param begin Iterator pointing to the beginning of the input sequence |
82 | /// \param end Iterator pointing to the end of the input sequence | 82 | /// \param end Iterator pointing to the end of the input sequence |
83 | /// | 83 | /// |
84 | /// \return Iterator pointing to one past the last read element of the input sequence | 84 | /// \return Iterator pointing to one past the last read element of the input sequence |
85 | /// | 85 | /// |
86 | //////////////////////////////////////////////////////////// | 86 | //////////////////////////////////////////////////////////// |
87 | template <typename In> static std::size_t Count( In begin, In end ); | 87 | template <typename In> static std::size_t Count( In begin, In end ); |
88 | 88 | ||
89 | //////////////////////////////////////////////////////////// | 89 | //////////////////////////////////////////////////////////// |
90 | /// \brief Convert an ANSI characters range to UTF-8 | 90 | /// \brief Convert an ANSI characters range to UTF-8 |
91 | /// | 91 | /// |
92 | /// The current global locale will be used by default, unless you | 92 | /// The current global locale will be used by default, unless you |
93 | /// pass a custom one in the \a locale parameter. | 93 | /// pass a custom one in the \a locale parameter. |
94 | /// | 94 | /// |
95 | /// \param begin Iterator pointing to the beginning of the input sequence | 95 | /// \param begin Iterator pointing to the beginning of the input sequence |
96 | /// \param end Iterator pointing to the end of the input sequence | 96 | /// \param end Iterator pointing to the end of the input sequence |
97 | /// \param output Iterator pointing to the beginning of the output sequence | 97 | /// \param output Iterator pointing to the beginning of the output sequence |
98 | /// \param locale Locale to use for conversion | 98 | /// \param locale Locale to use for conversion |
99 | /// | 99 | /// |
100 | /// \return Iterator to the end of the output sequence which has been written | 100 | /// \return Iterator to the end of the output sequence which has been written |
101 | /// | 101 | /// |
102 | //////////////////////////////////////////////////////////// | 102 | //////////////////////////////////////////////////////////// |
103 | template <typename In, typename Out> | 103 | template <typename In, typename Out> |
104 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 104 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
105 | 105 | ||
106 | //////////////////////////////////////////////////////////// | 106 | //////////////////////////////////////////////////////////// |
107 | /// \brief Convert a wide characters range to UTF-8 | 107 | /// \brief Convert a wide characters range to UTF-8 |
108 | /// | 108 | /// |
109 | /// \param begin Iterator pointing to the beginning of the input sequence | 109 | /// \param begin Iterator pointing to the beginning of the input sequence |
110 | /// \param end Iterator pointing to the end of the input sequence | 110 | /// \param end Iterator pointing to the end of the input sequence |
111 | /// \param output Iterator pointing to the beginning of the output sequence | 111 | /// \param output Iterator pointing to the beginning of the output sequence |
112 | /// | 112 | /// |
113 | /// \return Iterator to the end of the output sequence which has been written | 113 | /// \return Iterator to the end of the output sequence which has been written |
114 | /// | 114 | /// |
115 | //////////////////////////////////////////////////////////// | 115 | //////////////////////////////////////////////////////////// |
116 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 116 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
117 | 117 | ||
118 | //////////////////////////////////////////////////////////// | 118 | //////////////////////////////////////////////////////////// |
119 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 | 119 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 |
120 | /// | 120 | /// |
121 | /// \param begin Iterator pointing to the beginning of the input sequence | 121 | /// \param begin Iterator pointing to the beginning of the input sequence |
122 | /// \param end Iterator pointing to the end of the input sequence | 122 | /// \param end Iterator pointing to the end of the input sequence |
123 | /// \param output Iterator pointing to the beginning of the output sequence | 123 | /// \param output Iterator pointing to the beginning of the output sequence |
124 | /// \param locale Locale to use for conversion | 124 | /// \param locale Locale to use for conversion |
125 | /// | 125 | /// |
126 | /// \return Iterator to the end of the output sequence which has been written | 126 | /// \return Iterator to the end of the output sequence which has been written |
127 | /// | 127 | /// |
128 | //////////////////////////////////////////////////////////// | 128 | //////////////////////////////////////////////////////////// |
129 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 129 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
130 | 130 | ||
131 | //////////////////////////////////////////////////////////// | 131 | //////////////////////////////////////////////////////////// |
132 | /// \brief Convert an UTF-8 characters range to ANSI characters | 132 | /// \brief Convert an UTF-8 characters range to ANSI characters |
133 | /// | 133 | /// |
134 | /// The current global locale will be used by default, unless you | 134 | /// The current global locale will be used by default, unless you |
135 | /// pass a custom one in the \a locale parameter. | 135 | /// pass a custom one in the \a locale parameter. |
136 | /// | 136 | /// |
137 | /// \param begin Iterator pointing to the beginning of the input sequence | 137 | /// \param begin Iterator pointing to the beginning of the input sequence |
138 | /// \param end Iterator pointing to the end of the input sequence | 138 | /// \param end Iterator pointing to the end of the input sequence |
139 | /// \param output Iterator pointing to the beginning of the output sequence | 139 | /// \param output Iterator pointing to the beginning of the output sequence |
140 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 140 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
141 | /// \param locale Locale to use for conversion | 141 | /// \param locale Locale to use for conversion |
142 | /// | 142 | /// |
143 | /// \return Iterator to the end of the output sequence which has been written | 143 | /// \return Iterator to the end of the output sequence which has been written |
144 | /// | 144 | /// |
145 | //////////////////////////////////////////////////////////// | 145 | //////////////////////////////////////////////////////////// |
146 | template <typename In, typename Out> | 146 | template <typename In, typename Out> |
147 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 147 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
148 | const std::locale& locale = std::locale() ); | 148 | const std::locale& locale = std::locale() ); |
149 | 149 | ||
150 | #ifndef EFSW_NO_WIDECHAR | 150 | #ifndef EFSW_NO_WIDECHAR |
151 | //////////////////////////////////////////////////////////// | 151 | //////////////////////////////////////////////////////////// |
152 | /// \brief Convert an UTF-8 characters range to wide characters | 152 | /// \brief Convert an UTF-8 characters range to wide characters |
153 | /// | 153 | /// |
154 | /// \param begin Iterator pointing to the beginning of the input sequence | 154 | /// \param begin Iterator pointing to the beginning of the input sequence |
155 | /// \param end Iterator pointing to the end of the input sequence | 155 | /// \param end Iterator pointing to the end of the input sequence |
156 | /// \param output Iterator pointing to the beginning of the output sequence | 156 | /// \param output Iterator pointing to the beginning of the output sequence |
157 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 157 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
158 | /// | 158 | /// |
159 | /// \return Iterator to the end of the output sequence which has been written | 159 | /// \return Iterator to the end of the output sequence which has been written |
160 | /// | 160 | /// |
161 | //////////////////////////////////////////////////////////// | 161 | //////////////////////////////////////////////////////////// |
162 | template <typename In, typename Out> | 162 | template <typename In, typename Out> |
163 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 163 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | //////////////////////////////////////////////////////////// | 166 | //////////////////////////////////////////////////////////// |
167 | /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters | 167 | /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters |
168 | /// | 168 | /// |
169 | /// \param begin Iterator pointing to the beginning of the input sequence | 169 | /// \param begin Iterator pointing to the beginning of the input sequence |
170 | /// \param end Iterator pointing to the end of the input sequence | 170 | /// \param end Iterator pointing to the end of the input sequence |
171 | /// \param output Iterator pointing to the beginning of the output sequence | 171 | /// \param output Iterator pointing to the beginning of the output sequence |
172 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 172 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
173 | /// | 173 | /// |
174 | /// \return Iterator to the end of the output sequence which has been written | 174 | /// \return Iterator to the end of the output sequence which has been written |
175 | /// | 175 | /// |
176 | //////////////////////////////////////////////////////////// | 176 | //////////////////////////////////////////////////////////// |
177 | template <typename In, typename Out> | 177 | template <typename In, typename Out> |
178 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 178 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
179 | 179 | ||
180 | //////////////////////////////////////////////////////////// | 180 | //////////////////////////////////////////////////////////// |
181 | /// \brief Convert a UTF-8 characters range to UTF-8 | 181 | /// \brief Convert a UTF-8 characters range to UTF-8 |
182 | /// | 182 | /// |
183 | /// This functions does nothing more than a direct copy; | 183 | /// This functions does nothing more than a direct copy; |
184 | /// it is defined only to provide the same interface as other | 184 | /// it is defined only to provide the same interface as other |
185 | /// specializations of the efsw::Utf<> template, and allow | 185 | /// specializations of the efsw::Utf<> template, and allow |
186 | /// generic code to be written on top of it. | 186 | /// generic code to be written on top of it. |
187 | /// | 187 | /// |
188 | /// \param begin Iterator pointing to the beginning of the input sequence | 188 | /// \param begin Iterator pointing to the beginning of the input sequence |
189 | /// \param end Iterator pointing to the end of the input sequence | 189 | /// \param end Iterator pointing to the end of the input sequence |
190 | /// \param output Iterator pointing to the beginning of the output sequence | 190 | /// \param output Iterator pointing to the beginning of the output sequence |
191 | /// | 191 | /// |
192 | /// \return Iterator to the end of the output sequence which has been written | 192 | /// \return Iterator to the end of the output sequence which has been written |
193 | /// | 193 | /// |
194 | //////////////////////////////////////////////////////////// | 194 | //////////////////////////////////////////////////////////// |
195 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 195 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
196 | 196 | ||
197 | //////////////////////////////////////////////////////////// | 197 | //////////////////////////////////////////////////////////// |
198 | /// \brief Convert a UTF-8 characters range to UTF-16 | 198 | /// \brief Convert a UTF-8 characters range to UTF-16 |
199 | /// | 199 | /// |
200 | /// \param begin Iterator pointing to the beginning of the input sequence | 200 | /// \param begin Iterator pointing to the beginning of the input sequence |
201 | /// \param end Iterator pointing to the end of the input sequence | 201 | /// \param end Iterator pointing to the end of the input sequence |
202 | /// \param output Iterator pointing to the beginning of the output sequence | 202 | /// \param output Iterator pointing to the beginning of the output sequence |
203 | /// | 203 | /// |
204 | /// \return Iterator to the end of the output sequence which has been written | 204 | /// \return Iterator to the end of the output sequence which has been written |
205 | /// | 205 | /// |
206 | //////////////////////////////////////////////////////////// | 206 | //////////////////////////////////////////////////////////// |
207 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 207 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
208 | 208 | ||
209 | //////////////////////////////////////////////////////////// | 209 | //////////////////////////////////////////////////////////// |
210 | /// \brief Convert a UTF-8 characters range to UTF-32 | 210 | /// \brief Convert a UTF-8 characters range to UTF-32 |
211 | /// | 211 | /// |
212 | /// \param begin Iterator pointing to the beginning of the input sequence | 212 | /// \param begin Iterator pointing to the beginning of the input sequence |
213 | /// \param end Iterator pointing to the end of the input sequence | 213 | /// \param end Iterator pointing to the end of the input sequence |
214 | /// \param output Iterator pointing to the beginning of the output sequence | 214 | /// \param output Iterator pointing to the beginning of the output sequence |
215 | /// | 215 | /// |
216 | /// \return Iterator to the end of the output sequence which has been written | 216 | /// \return Iterator to the end of the output sequence which has been written |
217 | /// | 217 | /// |
218 | //////////////////////////////////////////////////////////// | 218 | //////////////////////////////////////////////////////////// |
219 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 219 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
220 | }; | 220 | }; |
221 | 221 | ||
222 | //////////////////////////////////////////////////////////// | 222 | //////////////////////////////////////////////////////////// |
223 | /// \brief Specialization of the Utf template for UTF-16 | 223 | /// \brief Specialization of the Utf template for UTF-16 |
224 | /// | 224 | /// |
225 | //////////////////////////////////////////////////////////// | 225 | //////////////////////////////////////////////////////////// |
226 | template <> class Utf<16> { | 226 | template <> class Utf<16> { |
227 | public: | 227 | public: |
228 | //////////////////////////////////////////////////////////// | 228 | //////////////////////////////////////////////////////////// |
229 | /// \brief Decode a single UTF-16 character | 229 | /// \brief Decode a single UTF-16 character |
230 | /// | 230 | /// |
231 | /// Decoding a character means finding its unique 32-bits | 231 | /// Decoding a character means finding its unique 32-bits |
232 | /// code (called the codepoint) in the Unicode standard. | 232 | /// code (called the codepoint) in the Unicode standard. |
233 | /// | 233 | /// |
234 | /// \param begin Iterator pointing to the beginning of the input sequence | 234 | /// \param begin Iterator pointing to the beginning of the input sequence |
235 | /// \param end Iterator pointing to the end of the input sequence | 235 | /// \param end Iterator pointing to the end of the input sequence |
236 | /// \param output Codepoint of the decoded UTF-16 character | 236 | /// \param output Codepoint of the decoded UTF-16 character |
237 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 237 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
238 | /// | 238 | /// |
239 | /// \return Iterator pointing to one past the last read element of the input sequence | 239 | /// \return Iterator pointing to one past the last read element of the input sequence |
240 | /// | 240 | /// |
241 | //////////////////////////////////////////////////////////// | 241 | //////////////////////////////////////////////////////////// |
242 | template <typename In> | 242 | template <typename In> |
243 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 243 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
244 | 244 | ||
245 | //////////////////////////////////////////////////////////// | 245 | //////////////////////////////////////////////////////////// |
246 | /// \brief Encode a single UTF-16 character | 246 | /// \brief Encode a single UTF-16 character |
247 | /// | 247 | /// |
248 | /// Encoding a character means converting a unique 32-bits | 248 | /// Encoding a character means converting a unique 32-bits |
249 | /// code (called the codepoint) in the target encoding, UTF-16. | 249 | /// code (called the codepoint) in the target encoding, UTF-16. |
250 | /// | 250 | /// |
251 | /// \param input Codepoint to encode as UTF-16 | 251 | /// \param input Codepoint to encode as UTF-16 |
252 | /// \param output Iterator pointing to the beginning of the output sequence | 252 | /// \param output Iterator pointing to the beginning of the output sequence |
253 | /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) | 253 | /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) |
254 | /// | 254 | /// |
255 | /// \return Iterator to the end of the output sequence which has been written | 255 | /// \return Iterator to the end of the output sequence which has been written |
256 | /// | 256 | /// |
257 | //////////////////////////////////////////////////////////// | 257 | //////////////////////////////////////////////////////////// |
258 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); | 258 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); |
259 | 259 | ||
260 | //////////////////////////////////////////////////////////// | 260 | //////////////////////////////////////////////////////////// |
261 | /// \brief Advance to the next UTF-16 character | 261 | /// \brief Advance to the next UTF-16 character |
262 | /// | 262 | /// |
263 | /// This function is necessary for multi-elements encodings, as | 263 | /// This function is necessary for multi-elements encodings, as |
264 | /// a single character may use more than 1 storage element. | 264 | /// a single character may use more than 1 storage element. |
265 | /// | 265 | /// |
266 | /// \param begin Iterator pointing to the beginning of the input sequence | 266 | /// \param begin Iterator pointing to the beginning of the input sequence |
267 | /// \param end Iterator pointing to the end of the input sequence | 267 | /// \param end Iterator pointing to the end of the input sequence |
268 | /// | 268 | /// |
269 | /// \return Iterator pointing to one past the last read element of the input sequence | 269 | /// \return Iterator pointing to one past the last read element of the input sequence |
270 | /// | 270 | /// |
271 | //////////////////////////////////////////////////////////// | 271 | //////////////////////////////////////////////////////////// |
272 | template <typename In> static In Next( In begin, In end ); | 272 | template <typename In> static In Next( In begin, In end ); |
273 | 273 | ||
274 | //////////////////////////////////////////////////////////// | 274 | //////////////////////////////////////////////////////////// |
275 | /// \brief Count the number of characters of a UTF-16 sequence | 275 | /// \brief Count the number of characters of a UTF-16 sequence |
276 | /// | 276 | /// |
277 | /// This function is necessary for multi-elements encodings, as | 277 | /// This function is necessary for multi-elements encodings, as |
278 | /// a single character may use more than 1 storage element, thus the | 278 | /// a single character may use more than 1 storage element, thus the |
279 | /// total size can be different from (begin - end). | 279 | /// total size can be different from (begin - end). |
280 | /// | 280 | /// |
281 | /// \param begin Iterator pointing to the beginning of the input sequence | 281 | /// \param begin Iterator pointing to the beginning of the input sequence |
282 | /// \param end Iterator pointing to the end of the input sequence | 282 | /// \param end Iterator pointing to the end of the input sequence |
283 | /// | 283 | /// |
284 | /// \return Iterator pointing to one past the last read element of the input sequence | 284 | /// \return Iterator pointing to one past the last read element of the input sequence |
285 | /// | 285 | /// |
286 | //////////////////////////////////////////////////////////// | 286 | //////////////////////////////////////////////////////////// |
287 | template <typename In> static std::size_t Count( In begin, In end ); | 287 | template <typename In> static std::size_t Count( In begin, In end ); |
288 | 288 | ||
289 | //////////////////////////////////////////////////////////// | 289 | //////////////////////////////////////////////////////////// |
290 | /// \brief Convert an ANSI characters range to UTF-16 | 290 | /// \brief Convert an ANSI characters range to UTF-16 |
291 | /// | 291 | /// |
292 | /// The current global locale will be used by default, unless you | 292 | /// The current global locale will be used by default, unless you |
293 | /// pass a custom one in the \a locale parameter. | 293 | /// pass a custom one in the \a locale parameter. |
294 | /// | 294 | /// |
295 | /// \param begin Iterator pointing to the beginning of the input sequence | 295 | /// \param begin Iterator pointing to the beginning of the input sequence |
296 | /// \param end Iterator pointing to the end of the input sequence | 296 | /// \param end Iterator pointing to the end of the input sequence |
297 | /// \param output Iterator pointing to the beginning of the output sequence | 297 | /// \param output Iterator pointing to the beginning of the output sequence |
298 | /// \param locale Locale to use for conversion | 298 | /// \param locale Locale to use for conversion |
299 | /// | 299 | /// |
300 | /// \return Iterator to the end of the output sequence which has been written | 300 | /// \return Iterator to the end of the output sequence which has been written |
301 | /// | 301 | /// |
302 | //////////////////////////////////////////////////////////// | 302 | //////////////////////////////////////////////////////////// |
303 | template <typename In, typename Out> | 303 | template <typename In, typename Out> |
304 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 304 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
305 | 305 | ||
306 | //////////////////////////////////////////////////////////// | 306 | //////////////////////////////////////////////////////////// |
307 | /// \brief Convert a wide characters range to UTF-16 | 307 | /// \brief Convert a wide characters range to UTF-16 |
308 | /// | 308 | /// |
309 | /// \param begin Iterator pointing to the beginning of the input sequence | 309 | /// \param begin Iterator pointing to the beginning of the input sequence |
310 | /// \param end Iterator pointing to the end of the input sequence | 310 | /// \param end Iterator pointing to the end of the input sequence |
311 | /// \param output Iterator pointing to the beginning of the output sequence | 311 | /// \param output Iterator pointing to the beginning of the output sequence |
312 | /// | 312 | /// |
313 | /// \return Iterator to the end of the output sequence which has been written | 313 | /// \return Iterator to the end of the output sequence which has been written |
314 | /// | 314 | /// |
315 | //////////////////////////////////////////////////////////// | 315 | //////////////////////////////////////////////////////////// |
316 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 316 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
317 | 317 | ||
318 | //////////////////////////////////////////////////////////// | 318 | //////////////////////////////////////////////////////////// |
319 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 | 319 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 |
320 | /// | 320 | /// |
321 | /// \param begin Iterator pointing to the beginning of the input sequence | 321 | /// \param begin Iterator pointing to the beginning of the input sequence |
322 | /// \param end Iterator pointing to the end of the input sequence | 322 | /// \param end Iterator pointing to the end of the input sequence |
323 | /// \param output Iterator pointing to the beginning of the output sequence | 323 | /// \param output Iterator pointing to the beginning of the output sequence |
324 | /// \param locale Locale to use for conversion | 324 | /// \param locale Locale to use for conversion |
325 | /// | 325 | /// |
326 | /// \return Iterator to the end of the output sequence which has been written | 326 | /// \return Iterator to the end of the output sequence which has been written |
327 | /// | 327 | /// |
328 | //////////////////////////////////////////////////////////// | 328 | //////////////////////////////////////////////////////////// |
329 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 329 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
330 | 330 | ||
331 | //////////////////////////////////////////////////////////// | 331 | //////////////////////////////////////////////////////////// |
332 | /// \brief Convert an UTF-16 characters range to ANSI characters | 332 | /// \brief Convert an UTF-16 characters range to ANSI characters |
333 | /// | 333 | /// |
334 | /// The current global locale will be used by default, unless you | 334 | /// The current global locale will be used by default, unless you |
335 | /// pass a custom one in the \a locale parameter. | 335 | /// pass a custom one in the \a locale parameter. |
336 | /// | 336 | /// |
337 | /// \param begin Iterator pointing to the beginning of the input sequence | 337 | /// \param begin Iterator pointing to the beginning of the input sequence |
338 | /// \param end Iterator pointing to the end of the input sequence | 338 | /// \param end Iterator pointing to the end of the input sequence |
339 | /// \param output Iterator pointing to the beginning of the output sequence | 339 | /// \param output Iterator pointing to the beginning of the output sequence |
340 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 340 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
341 | /// \param locale Locale to use for conversion | 341 | /// \param locale Locale to use for conversion |
342 | /// | 342 | /// |
343 | /// \return Iterator to the end of the output sequence which has been written | 343 | /// \return Iterator to the end of the output sequence which has been written |
344 | /// | 344 | /// |
345 | //////////////////////////////////////////////////////////// | 345 | //////////////////////////////////////////////////////////// |
346 | template <typename In, typename Out> | 346 | template <typename In, typename Out> |
347 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 347 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
348 | const std::locale& locale = std::locale() ); | 348 | const std::locale& locale = std::locale() ); |
349 | 349 | ||
350 | #ifndef EFSW_NO_WIDECHAR | 350 | #ifndef EFSW_NO_WIDECHAR |
351 | //////////////////////////////////////////////////////////// | 351 | //////////////////////////////////////////////////////////// |
352 | /// \brief Convert an UTF-16 characters range to wide characters | 352 | /// \brief Convert an UTF-16 characters range to wide characters |
353 | /// | 353 | /// |
354 | /// \param begin Iterator pointing to the beginning of the input sequence | 354 | /// \param begin Iterator pointing to the beginning of the input sequence |
355 | /// \param end Iterator pointing to the end of the input sequence | 355 | /// \param end Iterator pointing to the end of the input sequence |
356 | /// \param output Iterator pointing to the beginning of the output sequence | 356 | /// \param output Iterator pointing to the beginning of the output sequence |
357 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 357 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
358 | /// | 358 | /// |
359 | /// \return Iterator to the end of the output sequence which has been written | 359 | /// \return Iterator to the end of the output sequence which has been written |
360 | /// | 360 | /// |
361 | //////////////////////////////////////////////////////////// | 361 | //////////////////////////////////////////////////////////// |
362 | template <typename In, typename Out> | 362 | template <typename In, typename Out> |
363 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 363 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
364 | #endif | 364 | #endif |
365 | 365 | ||
366 | //////////////////////////////////////////////////////////// | 366 | //////////////////////////////////////////////////////////// |
367 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | 367 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters |
368 | /// | 368 | /// |
369 | /// \param begin Iterator pointing to the beginning of the input sequence | 369 | /// \param begin Iterator pointing to the beginning of the input sequence |
370 | /// \param end Iterator pointing to the end of the input sequence | 370 | /// \param end Iterator pointing to the end of the input sequence |
371 | /// \param output Iterator pointing to the beginning of the output sequence | 371 | /// \param output Iterator pointing to the beginning of the output sequence |
372 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 372 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
373 | /// | 373 | /// |
374 | /// \return Iterator to the end of the output sequence which has been written | 374 | /// \return Iterator to the end of the output sequence which has been written |
375 | /// | 375 | /// |
376 | //////////////////////////////////////////////////////////// | 376 | //////////////////////////////////////////////////////////// |
377 | template <typename In, typename Out> | 377 | template <typename In, typename Out> |
378 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 378 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
379 | 379 | ||
380 | //////////////////////////////////////////////////////////// | 380 | //////////////////////////////////////////////////////////// |
381 | /// \brief Convert a UTF-16 characters range to UTF-8 | 381 | /// \brief Convert a UTF-16 characters range to UTF-8 |
382 | /// | 382 | /// |
383 | /// \param begin Iterator pointing to the beginning of the input sequence | 383 | /// \param begin Iterator pointing to the beginning of the input sequence |
384 | /// \param end Iterator pointing to the end of the input sequence | 384 | /// \param end Iterator pointing to the end of the input sequence |
385 | /// \param output Iterator pointing to the beginning of the output sequence | 385 | /// \param output Iterator pointing to the beginning of the output sequence |
386 | /// | 386 | /// |
387 | /// \return Iterator to the end of the output sequence which has been written | 387 | /// \return Iterator to the end of the output sequence which has been written |
388 | /// | 388 | /// |
389 | //////////////////////////////////////////////////////////// | 389 | //////////////////////////////////////////////////////////// |
390 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 390 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
391 | 391 | ||
392 | //////////////////////////////////////////////////////////// | 392 | //////////////////////////////////////////////////////////// |
393 | /// \brief Convert a UTF-16 characters range to UTF-16 | 393 | /// \brief Convert a UTF-16 characters range to UTF-16 |
394 | /// | 394 | /// |
395 | /// This functions does nothing more than a direct copy; | 395 | /// This functions does nothing more than a direct copy; |
396 | /// it is defined only to provide the same interface as other | 396 | /// it is defined only to provide the same interface as other |
397 | /// specializations of the efsw::Utf<> template, and allow | 397 | /// specializations of the efsw::Utf<> template, and allow |
398 | /// generic code to be written on top of it. | 398 | /// generic code to be written on top of it. |
399 | /// | 399 | /// |
400 | /// \param begin Iterator pointing to the beginning of the input sequence | 400 | /// \param begin Iterator pointing to the beginning of the input sequence |
401 | /// \param end Iterator pointing to the end of the input sequence | 401 | /// \param end Iterator pointing to the end of the input sequence |
402 | /// \param output Iterator pointing to the beginning of the output sequence | 402 | /// \param output Iterator pointing to the beginning of the output sequence |
403 | /// | 403 | /// |
404 | /// \return Iterator to the end of the output sequence which has been written | 404 | /// \return Iterator to the end of the output sequence which has been written |
405 | /// | 405 | /// |
406 | //////////////////////////////////////////////////////////// | 406 | //////////////////////////////////////////////////////////// |
407 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 407 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
408 | 408 | ||
409 | //////////////////////////////////////////////////////////// | 409 | //////////////////////////////////////////////////////////// |
410 | /// \brief Convert a UTF-16 characters range to UTF-32 | 410 | /// \brief Convert a UTF-16 characters range to UTF-32 |
411 | /// | 411 | /// |
412 | /// \param begin Iterator pointing to the beginning of the input sequence | 412 | /// \param begin Iterator pointing to the beginning of the input sequence |
413 | /// \param end Iterator pointing to the end of the input sequence | 413 | /// \param end Iterator pointing to the end of the input sequence |
414 | /// \param output Iterator pointing to the beginning of the output sequence | 414 | /// \param output Iterator pointing to the beginning of the output sequence |
415 | /// | 415 | /// |
416 | /// \return Iterator to the end of the output sequence which has been written | 416 | /// \return Iterator to the end of the output sequence which has been written |
417 | /// | 417 | /// |
418 | //////////////////////////////////////////////////////////// | 418 | //////////////////////////////////////////////////////////// |
419 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 419 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
420 | }; | 420 | }; |
421 | 421 | ||
422 | //////////////////////////////////////////////////////////// | 422 | //////////////////////////////////////////////////////////// |
423 | /// \brief Specialization of the Utf template for UTF-32 | 423 | /// \brief Specialization of the Utf template for UTF-32 |
424 | /// | 424 | /// |
425 | //////////////////////////////////////////////////////////// | 425 | //////////////////////////////////////////////////////////// |
426 | template <> class Utf<32> { | 426 | template <> class Utf<32> { |
427 | public: | 427 | public: |
428 | //////////////////////////////////////////////////////////// | 428 | //////////////////////////////////////////////////////////// |
429 | /// \brief Decode a single UTF-32 character | 429 | /// \brief Decode a single UTF-32 character |
430 | /// | 430 | /// |
431 | /// Decoding a character means finding its unique 32-bits | 431 | /// Decoding a character means finding its unique 32-bits |
432 | /// code (called the codepoint) in the Unicode standard. | 432 | /// code (called the codepoint) in the Unicode standard. |
433 | /// For UTF-32, the character value is the same as the codepoint. | 433 | /// For UTF-32, the character value is the same as the codepoint. |
434 | /// | 434 | /// |
435 | /// \param begin Iterator pointing to the beginning of the input sequence | 435 | /// \param begin Iterator pointing to the beginning of the input sequence |
436 | /// \param end Iterator pointing to the end of the input sequence | 436 | /// \param end Iterator pointing to the end of the input sequence |
437 | /// \param output Codepoint of the decoded UTF-32 character | 437 | /// \param output Codepoint of the decoded UTF-32 character |
438 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 438 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
439 | /// | 439 | /// |
440 | /// \return Iterator pointing to one past the last read element of the input sequence | 440 | /// \return Iterator pointing to one past the last read element of the input sequence |
441 | /// | 441 | /// |
442 | //////////////////////////////////////////////////////////// | 442 | //////////////////////////////////////////////////////////// |
443 | template <typename In> | 443 | template <typename In> |
444 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 444 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
445 | 445 | ||
446 | //////////////////////////////////////////////////////////// | 446 | //////////////////////////////////////////////////////////// |
447 | /// \brief Encode a single UTF-32 character | 447 | /// \brief Encode a single UTF-32 character |
448 | /// | 448 | /// |
449 | /// Encoding a character means converting a unique 32-bits | 449 | /// Encoding a character means converting a unique 32-bits |
450 | /// code (called the codepoint) in the target encoding, UTF-32. | 450 | /// code (called the codepoint) in the target encoding, UTF-32. |
451 | /// For UTF-32, the codepoint is the same as the character value. | 451 | /// For UTF-32, the codepoint is the same as the character value. |
452 | /// | 452 | /// |
453 | /// \param input Codepoint to encode as UTF-32 | 453 | /// \param input Codepoint to encode as UTF-32 |
454 | /// \param output Iterator pointing to the beginning of the output sequence | 454 | /// \param output Iterator pointing to the beginning of the output sequence |
455 | /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) | 455 | /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) |
456 | /// | 456 | /// |
457 | /// \return Iterator to the end of the output sequence which has been written | 457 | /// \return Iterator to the end of the output sequence which has been written |
458 | /// | 458 | /// |
459 | //////////////////////////////////////////////////////////// | 459 | //////////////////////////////////////////////////////////// |
460 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); | 460 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); |
461 | 461 | ||
462 | //////////////////////////////////////////////////////////// | 462 | //////////////////////////////////////////////////////////// |
463 | /// \brief Advance to the next UTF-32 character | 463 | /// \brief Advance to the next UTF-32 character |
464 | /// | 464 | /// |
465 | /// This function is trivial for UTF-32, which can store | 465 | /// This function is trivial for UTF-32, which can store |
466 | /// every character in a single storage element. | 466 | /// every character in a single storage element. |
467 | /// | 467 | /// |
468 | /// \param begin Iterator pointing to the beginning of the input sequence | 468 | /// \param begin Iterator pointing to the beginning of the input sequence |
469 | /// \param end Iterator pointing to the end of the input sequence | 469 | /// \param end Iterator pointing to the end of the input sequence |
470 | /// | 470 | /// |
471 | /// \return Iterator pointing to one past the last read element of the input sequence | 471 | /// \return Iterator pointing to one past the last read element of the input sequence |
472 | /// | 472 | /// |
473 | //////////////////////////////////////////////////////////// | 473 | //////////////////////////////////////////////////////////// |
474 | template <typename In> static In Next( In begin, In end ); | 474 | template <typename In> static In Next( In begin, In end ); |
475 | 475 | ||
476 | //////////////////////////////////////////////////////////// | 476 | //////////////////////////////////////////////////////////// |
477 | /// \brief Count the number of characters of a UTF-32 sequence | 477 | /// \brief Count the number of characters of a UTF-32 sequence |
478 | /// | 478 | /// |
479 | /// This function is trivial for UTF-32, which can store | 479 | /// This function is trivial for UTF-32, which can store |
480 | /// every character in a single storage element. | 480 | /// every character in a single storage element. |
481 | /// | 481 | /// |
482 | /// \param begin Iterator pointing to the beginning of the input sequence | 482 | /// \param begin Iterator pointing to the beginning of the input sequence |
483 | /// \param end Iterator pointing to the end of the input sequence | 483 | /// \param end Iterator pointing to the end of the input sequence |
484 | /// | 484 | /// |
485 | /// \return Iterator pointing to one past the last read element of the input sequence | 485 | /// \return Iterator pointing to one past the last read element of the input sequence |
486 | /// | 486 | /// |
487 | //////////////////////////////////////////////////////////// | 487 | //////////////////////////////////////////////////////////// |
488 | template <typename In> static std::size_t Count( In begin, In end ); | 488 | template <typename In> static std::size_t Count( In begin, In end ); |
489 | 489 | ||
490 | //////////////////////////////////////////////////////////// | 490 | //////////////////////////////////////////////////////////// |
491 | /// \brief Convert an ANSI characters range to UTF-32 | 491 | /// \brief Convert an ANSI characters range to UTF-32 |
492 | /// | 492 | /// |
493 | /// The current global locale will be used by default, unless you | 493 | /// The current global locale will be used by default, unless you |
494 | /// pass a custom one in the \a locale parameter. | 494 | /// pass a custom one in the \a locale parameter. |
495 | /// | 495 | /// |
496 | /// \param begin Iterator pointing to the beginning of the input sequence | 496 | /// \param begin Iterator pointing to the beginning of the input sequence |
497 | /// \param end Iterator pointing to the end of the input sequence | 497 | /// \param end Iterator pointing to the end of the input sequence |
498 | /// \param output Iterator pointing to the beginning of the output sequence | 498 | /// \param output Iterator pointing to the beginning of the output sequence |
499 | /// \param locale Locale to use for conversion | 499 | /// \param locale Locale to use for conversion |
500 | /// | 500 | /// |
501 | /// \return Iterator to the end of the output sequence which has been written | 501 | /// \return Iterator to the end of the output sequence which has been written |
502 | /// | 502 | /// |
503 | //////////////////////////////////////////////////////////// | 503 | //////////////////////////////////////////////////////////// |
504 | template <typename In, typename Out> | 504 | template <typename In, typename Out> |
505 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 505 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
506 | 506 | ||
507 | //////////////////////////////////////////////////////////// | 507 | //////////////////////////////////////////////////////////// |
508 | /// \brief Convert a wide characters range to UTF-32 | 508 | /// \brief Convert a wide characters range to UTF-32 |
509 | /// | 509 | /// |
510 | /// \param begin Iterator pointing to the beginning of the input sequence | 510 | /// \param begin Iterator pointing to the beginning of the input sequence |
511 | /// \param end Iterator pointing to the end of the input sequence | 511 | /// \param end Iterator pointing to the end of the input sequence |
512 | /// \param output Iterator pointing to the beginning of the output sequence | 512 | /// \param output Iterator pointing to the beginning of the output sequence |
513 | /// | 513 | /// |
514 | /// \return Iterator to the end of the output sequence which has been written | 514 | /// \return Iterator to the end of the output sequence which has been written |
515 | /// | 515 | /// |
516 | //////////////////////////////////////////////////////////// | 516 | //////////////////////////////////////////////////////////// |
517 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 517 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
518 | 518 | ||
519 | //////////////////////////////////////////////////////////// | 519 | //////////////////////////////////////////////////////////// |
520 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 | 520 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 |
521 | /// | 521 | /// |
522 | /// \param begin Iterator pointing to the beginning of the input sequence | 522 | /// \param begin Iterator pointing to the beginning of the input sequence |
523 | /// \param end Iterator pointing to the end of the input sequence | 523 | /// \param end Iterator pointing to the end of the input sequence |
524 | /// \param output Iterator pointing to the beginning of the output sequence | 524 | /// \param output Iterator pointing to the beginning of the output sequence |
525 | /// \param locale Locale to use for conversion | 525 | /// \param locale Locale to use for conversion |
526 | /// | 526 | /// |
527 | /// \return Iterator to the end of the output sequence which has been written | 527 | /// \return Iterator to the end of the output sequence which has been written |
528 | /// | 528 | /// |
529 | //////////////////////////////////////////////////////////// | 529 | //////////////////////////////////////////////////////////// |
530 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 530 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
531 | 531 | ||
532 | //////////////////////////////////////////////////////////// | 532 | //////////////////////////////////////////////////////////// |
533 | /// \brief Convert an UTF-32 characters range to ANSI characters | 533 | /// \brief Convert an UTF-32 characters range to ANSI characters |
534 | /// | 534 | /// |
535 | /// The current global locale will be used by default, unless you | 535 | /// The current global locale will be used by default, unless you |
536 | /// pass a custom one in the \a locale parameter. | 536 | /// pass a custom one in the \a locale parameter. |
537 | /// | 537 | /// |
538 | /// \param begin Iterator pointing to the beginning of the input sequence | 538 | /// \param begin Iterator pointing to the beginning of the input sequence |
539 | /// \param end Iterator pointing to the end of the input sequence | 539 | /// \param end Iterator pointing to the end of the input sequence |
540 | /// \param output Iterator pointing to the beginning of the output sequence | 540 | /// \param output Iterator pointing to the beginning of the output sequence |
541 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 541 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
542 | /// \param locale Locale to use for conversion | 542 | /// \param locale Locale to use for conversion |
543 | /// | 543 | /// |
544 | /// \return Iterator to the end of the output sequence which has been written | 544 | /// \return Iterator to the end of the output sequence which has been written |
545 | /// | 545 | /// |
546 | //////////////////////////////////////////////////////////// | 546 | //////////////////////////////////////////////////////////// |
547 | template <typename In, typename Out> | 547 | template <typename In, typename Out> |
548 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 548 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
549 | const std::locale& locale = std::locale() ); | 549 | const std::locale& locale = std::locale() ); |
550 | 550 | ||
551 | #ifndef EFSW_NO_WIDECHAR | 551 | #ifndef EFSW_NO_WIDECHAR |
552 | //////////////////////////////////////////////////////////// | 552 | //////////////////////////////////////////////////////////// |
553 | /// \brief Convert an UTF-32 characters range to wide characters | 553 | /// \brief Convert an UTF-32 characters range to wide characters |
554 | /// | 554 | /// |
555 | /// \param begin Iterator pointing to the beginning of the input sequence | 555 | /// \param begin Iterator pointing to the beginning of the input sequence |
556 | /// \param end Iterator pointing to the end of the input sequence | 556 | /// \param end Iterator pointing to the end of the input sequence |
557 | /// \param output Iterator pointing to the beginning of the output sequence | 557 | /// \param output Iterator pointing to the beginning of the output sequence |
558 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 558 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
559 | /// | 559 | /// |
560 | /// \return Iterator to the end of the output sequence which has been written | 560 | /// \return Iterator to the end of the output sequence which has been written |
561 | /// | 561 | /// |
562 | //////////////////////////////////////////////////////////// | 562 | //////////////////////////////////////////////////////////// |
563 | template <typename In, typename Out> | 563 | template <typename In, typename Out> |
564 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 564 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
565 | #endif | 565 | #endif |
566 | 566 | ||
567 | //////////////////////////////////////////////////////////// | 567 | //////////////////////////////////////////////////////////// |
568 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | 568 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters |
569 | /// | 569 | /// |
570 | /// \param begin Iterator pointing to the beginning of the input sequence | 570 | /// \param begin Iterator pointing to the beginning of the input sequence |
571 | /// \param end Iterator pointing to the end of the input sequence | 571 | /// \param end Iterator pointing to the end of the input sequence |
572 | /// \param output Iterator pointing to the beginning of the output sequence | 572 | /// \param output Iterator pointing to the beginning of the output sequence |
573 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 573 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
574 | /// | 574 | /// |
575 | /// \return Iterator to the end of the output sequence which has been written | 575 | /// \return Iterator to the end of the output sequence which has been written |
576 | /// | 576 | /// |
577 | //////////////////////////////////////////////////////////// | 577 | //////////////////////////////////////////////////////////// |
578 | template <typename In, typename Out> | 578 | template <typename In, typename Out> |
579 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 579 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
580 | 580 | ||
581 | //////////////////////////////////////////////////////////// | 581 | //////////////////////////////////////////////////////////// |
582 | /// \brief Convert a UTF-32 characters range to UTF-8 | 582 | /// \brief Convert a UTF-32 characters range to UTF-8 |
583 | /// | 583 | /// |
584 | /// \param begin Iterator pointing to the beginning of the input sequence | 584 | /// \param begin Iterator pointing to the beginning of the input sequence |
585 | /// \param end Iterator pointing to the end of the input sequence | 585 | /// \param end Iterator pointing to the end of the input sequence |
586 | /// \param output Iterator pointing to the beginning of the output sequence | 586 | /// \param output Iterator pointing to the beginning of the output sequence |
587 | /// | 587 | /// |
588 | /// \return Iterator to the end of the output sequence which has been written | 588 | /// \return Iterator to the end of the output sequence which has been written |
589 | /// | 589 | /// |
590 | //////////////////////////////////////////////////////////// | 590 | //////////////////////////////////////////////////////////// |
591 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 591 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
592 | 592 | ||
593 | //////////////////////////////////////////////////////////// | 593 | //////////////////////////////////////////////////////////// |
594 | /// \brief Convert a UTF-32 characters range to UTF-16 | 594 | /// \brief Convert a UTF-32 characters range to UTF-16 |
595 | /// | 595 | /// |
596 | /// \param begin Iterator pointing to the beginning of the input sequence | 596 | /// \param begin Iterator pointing to the beginning of the input sequence |
597 | /// \param end Iterator pointing to the end of the input sequence | 597 | /// \param end Iterator pointing to the end of the input sequence |
598 | /// \param output Iterator pointing to the beginning of the output sequence | 598 | /// \param output Iterator pointing to the beginning of the output sequence |
599 | /// | 599 | /// |
600 | /// \return Iterator to the end of the output sequence which has been written | 600 | /// \return Iterator to the end of the output sequence which has been written |
601 | /// | 601 | /// |
602 | //////////////////////////////////////////////////////////// | 602 | //////////////////////////////////////////////////////////// |
603 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 603 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
604 | 604 | ||
605 | //////////////////////////////////////////////////////////// | 605 | //////////////////////////////////////////////////////////// |
606 | /// \brief Convert a UTF-32 characters range to UTF-32 | 606 | /// \brief Convert a UTF-32 characters range to UTF-32 |
607 | /// | 607 | /// |
608 | /// This functions does nothing more than a direct copy; | 608 | /// This functions does nothing more than a direct copy; |
609 | /// it is defined only to provide the same interface as other | 609 | /// it is defined only to provide the same interface as other |
610 | /// specializations of the efsw::Utf<> template, and allow | 610 | /// specializations of the efsw::Utf<> template, and allow |
611 | /// generic code to be written on top of it. | 611 | /// generic code to be written on top of it. |
612 | /// | 612 | /// |
613 | /// \param begin Iterator pointing to the beginning of the input sequence | 613 | /// \param begin Iterator pointing to the beginning of the input sequence |
614 | /// \param end Iterator pointing to the end of the input sequence | 614 | /// \param end Iterator pointing to the end of the input sequence |
615 | /// \param output Iterator pointing to the beginning of the output sequence | 615 | /// \param output Iterator pointing to the beginning of the output sequence |
616 | /// | 616 | /// |
617 | /// \return Iterator to the end of the output sequence which has been written | 617 | /// \return Iterator to the end of the output sequence which has been written |
618 | /// | 618 | /// |
619 | //////////////////////////////////////////////////////////// | 619 | //////////////////////////////////////////////////////////// |
620 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 620 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
621 | 621 | ||
622 | //////////////////////////////////////////////////////////// | 622 | //////////////////////////////////////////////////////////// |
623 | /// \brief Decode a single ANSI character to UTF-32 | 623 | /// \brief Decode a single ANSI character to UTF-32 |
624 | /// | 624 | /// |
625 | /// This function does not exist in other specializations | 625 | /// This function does not exist in other specializations |
626 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 626 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
627 | /// several other conversion functions). | 627 | /// several other conversion functions). |
628 | /// | 628 | /// |
629 | /// \param input Input ANSI character | 629 | /// \param input Input ANSI character |
630 | /// \param locale Locale to use for conversion | 630 | /// \param locale Locale to use for conversion |
631 | /// | 631 | /// |
632 | /// \return Converted character | 632 | /// \return Converted character |
633 | /// | 633 | /// |
634 | //////////////////////////////////////////////////////////// | 634 | //////////////////////////////////////////////////////////// |
635 | template <typename In> | 635 | template <typename In> |
636 | static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); | 636 | static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); |
637 | 637 | ||
638 | //////////////////////////////////////////////////////////// | 638 | //////////////////////////////////////////////////////////// |
639 | /// \brief Decode a single wide character to UTF-32 | 639 | /// \brief Decode a single wide character to UTF-32 |
640 | /// | 640 | /// |
641 | /// This function does not exist in other specializations | 641 | /// This function does not exist in other specializations |
642 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 642 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
643 | /// several other conversion functions). | 643 | /// several other conversion functions). |
644 | /// | 644 | /// |
645 | /// \param input Input wide character | 645 | /// \param input Input wide character |
646 | /// | 646 | /// |
647 | /// \return Converted character | 647 | /// \return Converted character |
648 | /// | 648 | /// |
649 | //////////////////////////////////////////////////////////// | 649 | //////////////////////////////////////////////////////////// |
650 | template <typename In> static Uint32 DecodeWide( In input ); | 650 | template <typename In> static Uint32 DecodeWide( In input ); |
651 | 651 | ||
652 | //////////////////////////////////////////////////////////// | 652 | //////////////////////////////////////////////////////////// |
653 | /// \brief Encode a single UTF-32 character to ANSI | 653 | /// \brief Encode a single UTF-32 character to ANSI |
654 | /// | 654 | /// |
655 | /// This function does not exist in other specializations | 655 | /// This function does not exist in other specializations |
656 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 656 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
657 | /// several other conversion functions). | 657 | /// several other conversion functions). |
658 | /// | 658 | /// |
659 | /// \param codepoint Iterator pointing to the beginning of the input sequence | 659 | /// \param codepoint Iterator pointing to the beginning of the input sequence |
660 | /// \param output Iterator pointing to the beginning of the output sequence | 660 | /// \param output Iterator pointing to the beginning of the output sequence |
661 | /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to | 661 | /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to |
662 | /// skip it) \param locale Locale to use for conversion | 662 | /// skip it) \param locale Locale to use for conversion |
663 | /// | 663 | /// |
664 | /// \return Iterator to the end of the output sequence which has been written | 664 | /// \return Iterator to the end of the output sequence which has been written |
665 | /// | 665 | /// |
666 | //////////////////////////////////////////////////////////// | 666 | //////////////////////////////////////////////////////////// |
667 | template <typename Out> | 667 | template <typename Out> |
668 | static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, | 668 | static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, |
669 | const std::locale& locale = std::locale() ); | 669 | const std::locale& locale = std::locale() ); |
670 | 670 | ||
671 | #ifndef EFSW_NO_WIDECHAR | 671 | #ifndef EFSW_NO_WIDECHAR |
672 | //////////////////////////////////////////////////////////// | 672 | //////////////////////////////////////////////////////////// |
673 | /// \brief Encode a single UTF-32 character to wide | 673 | /// \brief Encode a single UTF-32 character to wide |
674 | /// | 674 | /// |
675 | /// This function does not exist in other specializations | 675 | /// This function does not exist in other specializations |
676 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 676 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
677 | /// several other conversion functions). | 677 | /// several other conversion functions). |
678 | /// | 678 | /// |
679 | /// \param codepoint Iterator pointing to the beginning of the input sequence | 679 | /// \param codepoint Iterator pointing to the beginning of the input sequence |
680 | /// \param output Iterator pointing to the beginning of the output sequence | 680 | /// \param output Iterator pointing to the beginning of the output sequence |
681 | /// \param replacement Replacement if the input character is not convertible to wide (use 0 to | 681 | /// \param replacement Replacement if the input character is not convertible to wide (use 0 to |
682 | /// skip it) | 682 | /// skip it) |
683 | /// | 683 | /// |
684 | /// \return Iterator to the end of the output sequence which has been written | 684 | /// \return Iterator to the end of the output sequence which has been written |
685 | /// | 685 | /// |
686 | //////////////////////////////////////////////////////////// | 686 | //////////////////////////////////////////////////////////// |
687 | template <typename Out> | 687 | template <typename Out> |
688 | static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); | 688 | static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); |
689 | #endif | 689 | #endif |
690 | }; | 690 | }; |
691 | 691 | ||
692 | #include "Utf.inl" | 692 | #include "Utf.inl" |
693 | 693 | ||
694 | // Make typedefs to get rid of the template syntax | 694 | // Make typedefs to get rid of the template syntax |
695 | typedef Utf<8> Utf8; | 695 | typedef Utf<8> Utf8; |
696 | typedef Utf<16> Utf16; | 696 | typedef Utf<16> Utf16; |
697 | typedef Utf<32> Utf32; | 697 | typedef Utf<32> Utf32; |
698 | 698 | ||
699 | } // namespace efsw | 699 | } // namespace efsw |
700 | #endif | 700 | #endif |
701 | 701 | ||
702 | //////////////////////////////////////////////////////////// | 702 | //////////////////////////////////////////////////////////// |
703 | /// \class efsw::Utf | 703 | /// \class efsw::Utf |
704 | /// \ingroup system | 704 | /// \ingroup system |
705 | /// | 705 | /// |
706 | /// Utility class providing generic functions for UTF conversions. | 706 | /// Utility class providing generic functions for UTF conversions. |
707 | /// | 707 | /// |
708 | /// efsw::Utf is a low-level, generic interface for counting, iterating, | 708 | /// efsw::Utf is a low-level, generic interface for counting, iterating, |
709 | /// encoding and decoding Unicode characters and strings. It is able | 709 | /// encoding and decoding Unicode characters and strings. It is able |
710 | /// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. | 710 | /// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. |
711 | /// | 711 | /// |
712 | /// efsw::Utf<X> functions are all static, these classes are not meant to | 712 | /// efsw::Utf<X> functions are all static, these classes are not meant to |
713 | /// be instanciated. All the functions are template, so that you | 713 | /// be instanciated. All the functions are template, so that you |
714 | /// can use any character / string type for a given encoding. | 714 | /// can use any character / string type for a given encoding. |
715 | /// | 715 | /// |
716 | /// It has 3 specializations: | 716 | /// It has 3 specializations: |
717 | /// \li efsw::Utf<8> (typedef'd to efsw::Utf8) | 717 | /// \li efsw::Utf<8> (typedef'd to efsw::Utf8) |
718 | /// \li efsw::Utf<16> (typedef'd to efsw::Utf16) | 718 | /// \li efsw::Utf<16> (typedef'd to efsw::Utf16) |
719 | /// \li efsw::Utf<32> (typedef'd to efsw::Utf32) | 719 | /// \li efsw::Utf<32> (typedef'd to efsw::Utf32) |
720 | /// | 720 | /// |
721 | //////////////////////////////////////////////////////////// | 721 | //////////////////////////////////////////////////////////// |
diff --git a/src/3rdParty/efsw/Utf.inl b/src/3rdParty/efsw/Utf.inl index 5b6c2e0..5c9d7a3 100755..100644 --- a/src/3rdParty/efsw/Utf.inl +++ b/src/3rdParty/efsw/Utf.inl | |||
@@ -1,576 +1,576 @@ | |||
1 | // References : | 1 | // References : |
2 | // http://www.unicode.org/ | 2 | // http://www.unicode.org/ |
3 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c | 3 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c |
4 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h | 4 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h |
5 | // http://people.w3.org/rishida/scripts/uniview/conversion | 5 | // http://people.w3.org/rishida/scripts/uniview/conversion |
6 | //////////////////////////////////////////////////////////// | 6 | //////////////////////////////////////////////////////////// |
7 | 7 | ||
8 | template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | 8 | template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { |
9 | // Some useful precomputed data | 9 | // Some useful precomputed data |
10 | static const int trailing[256] = { | 10 | static const int trailing[256] = { |
11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, | 18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, |
19 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; | 19 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; |
20 | static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, | 20 | static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, |
21 | 0x03C82080, 0xFA082080, 0x82082080 }; | 21 | 0x03C82080, 0xFA082080, 0x82082080 }; |
22 | 22 | ||
23 | // Decode the character | 23 | // Decode the character |
24 | int trailingBytes = trailing[static_cast<Uint8>( *begin )]; | 24 | int trailingBytes = trailing[static_cast<Uint8>( *begin )]; |
25 | if ( begin + trailingBytes < end ) { | 25 | if ( begin + trailingBytes < end ) { |
26 | output = 0; | 26 | output = 0; |
27 | switch ( trailingBytes ) { | 27 | switch ( trailingBytes ) { |
28 | case 5: | 28 | case 5: |
29 | output += static_cast<Uint8>( *begin++ ); | 29 | output += static_cast<Uint8>( *begin++ ); |
30 | output <<= 6; | 30 | output <<= 6; |
31 | case 4: | 31 | case 4: |
32 | output += static_cast<Uint8>( *begin++ ); | 32 | output += static_cast<Uint8>( *begin++ ); |
33 | output <<= 6; | 33 | output <<= 6; |
34 | case 3: | 34 | case 3: |
35 | output += static_cast<Uint8>( *begin++ ); | 35 | output += static_cast<Uint8>( *begin++ ); |
36 | output <<= 6; | 36 | output <<= 6; |
37 | case 2: | 37 | case 2: |
38 | output += static_cast<Uint8>( *begin++ ); | 38 | output += static_cast<Uint8>( *begin++ ); |
39 | output <<= 6; | 39 | output <<= 6; |
40 | case 1: | 40 | case 1: |
41 | output += static_cast<Uint8>( *begin++ ); | 41 | output += static_cast<Uint8>( *begin++ ); |
42 | output <<= 6; | 42 | output <<= 6; |
43 | case 0: | 43 | case 0: |
44 | output += static_cast<Uint8>( *begin++ ); | 44 | output += static_cast<Uint8>( *begin++ ); |
45 | } | 45 | } |
46 | output -= offsets[trailingBytes]; | 46 | output -= offsets[trailingBytes]; |
47 | } else { | 47 | } else { |
48 | // Incomplete character | 48 | // Incomplete character |
49 | begin = end; | 49 | begin = end; |
50 | output = replacement; | 50 | output = replacement; |
51 | } | 51 | } |
52 | 52 | ||
53 | return begin; | 53 | return begin; |
54 | } | 54 | } |
55 | 55 | ||
56 | template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { | 56 | template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { |
57 | // Some useful precomputed data | 57 | // Some useful precomputed data |
58 | static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | 58 | static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; |
59 | 59 | ||
60 | // Encode the character | 60 | // Encode the character |
61 | if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { | 61 | if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { |
62 | // Invalid character | 62 | // Invalid character |
63 | if ( replacement ) | 63 | if ( replacement ) |
64 | *output++ = replacement; | 64 | *output++ = replacement; |
65 | } else { | 65 | } else { |
66 | // Valid character | 66 | // Valid character |
67 | 67 | ||
68 | // Get the number of bytes to write | 68 | // Get the number of bytes to write |
69 | int bytesToWrite = 1; | 69 | int bytesToWrite = 1; |
70 | if ( input < 0x80 ) | 70 | if ( input < 0x80 ) |
71 | bytesToWrite = 1; | 71 | bytesToWrite = 1; |
72 | else if ( input < 0x800 ) | 72 | else if ( input < 0x800 ) |
73 | bytesToWrite = 2; | 73 | bytesToWrite = 2; |
74 | else if ( input < 0x10000 ) | 74 | else if ( input < 0x10000 ) |
75 | bytesToWrite = 3; | 75 | bytesToWrite = 3; |
76 | else if ( input <= 0x0010FFFF ) | 76 | else if ( input <= 0x0010FFFF ) |
77 | bytesToWrite = 4; | 77 | bytesToWrite = 4; |
78 | 78 | ||
79 | // Extract the bytes to write | 79 | // Extract the bytes to write |
80 | Uint8 bytes[4]; | 80 | Uint8 bytes[4]; |
81 | switch ( bytesToWrite ) { | 81 | switch ( bytesToWrite ) { |
82 | case 4: | 82 | case 4: |
83 | bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 83 | bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
84 | input >>= 6; | 84 | input >>= 6; |
85 | case 3: | 85 | case 3: |
86 | bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 86 | bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
87 | input >>= 6; | 87 | input >>= 6; |
88 | case 2: | 88 | case 2: |
89 | bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 89 | bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
90 | input >>= 6; | 90 | input >>= 6; |
91 | case 1: | 91 | case 1: |
92 | bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); | 92 | bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); |
93 | } | 93 | } |
94 | 94 | ||
95 | // Add them to the output | 95 | // Add them to the output |
96 | const Uint8* currentByte = bytes; | 96 | const Uint8* currentByte = bytes; |
97 | switch ( bytesToWrite ) { | 97 | switch ( bytesToWrite ) { |
98 | case 4: | 98 | case 4: |
99 | *output++ = *currentByte++; | 99 | *output++ = *currentByte++; |
100 | case 3: | 100 | case 3: |
101 | *output++ = *currentByte++; | 101 | *output++ = *currentByte++; |
102 | case 2: | 102 | case 2: |
103 | *output++ = *currentByte++; | 103 | *output++ = *currentByte++; |
104 | case 1: | 104 | case 1: |
105 | *output++ = *currentByte++; | 105 | *output++ = *currentByte++; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | return output; | 109 | return output; |
110 | } | 110 | } |
111 | 111 | ||
112 | template <typename In> In Utf<8>::Next( In begin, In end ) { | 112 | template <typename In> In Utf<8>::Next( In begin, In end ) { |
113 | Uint32 codepoint; | 113 | Uint32 codepoint; |
114 | return Decode( begin, end, codepoint ); | 114 | return Decode( begin, end, codepoint ); |
115 | } | 115 | } |
116 | 116 | ||
117 | template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { | 117 | template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { |
118 | std::size_t length = 0; | 118 | std::size_t length = 0; |
119 | while ( begin < end ) { | 119 | while ( begin < end ) { |
120 | begin = Next( begin, end ); | 120 | begin = Next( begin, end ); |
121 | ++length; | 121 | ++length; |
122 | } | 122 | } |
123 | 123 | ||
124 | return length; | 124 | return length; |
125 | } | 125 | } |
126 | 126 | ||
127 | template <typename In, typename Out> | 127 | template <typename In, typename Out> |
128 | Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 128 | Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
129 | while ( begin < end ) { | 129 | while ( begin < end ) { |
130 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | 130 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); |
131 | output = Encode( codepoint, output ); | 131 | output = Encode( codepoint, output ); |
132 | } | 132 | } |
133 | 133 | ||
134 | return output; | 134 | return output; |
135 | } | 135 | } |
136 | 136 | ||
137 | template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { | 137 | template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { |
138 | while ( begin < end ) { | 138 | while ( begin < end ) { |
139 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | 139 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); |
140 | output = Encode( codepoint, output ); | 140 | output = Encode( codepoint, output ); |
141 | } | 141 | } |
142 | 142 | ||
143 | return output; | 143 | return output; |
144 | } | 144 | } |
145 | 145 | ||
146 | template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { | 146 | template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { |
147 | // Latin-1 is directly compatible with Unicode encodings, | 147 | // Latin-1 is directly compatible with Unicode encodings, |
148 | // and can thus be treated as (a sub-range of) UTF-32 | 148 | // and can thus be treated as (a sub-range of) UTF-32 |
149 | while ( begin < end ) | 149 | while ( begin < end ) |
150 | output = Encode( *begin++, output ); | 150 | output = Encode( *begin++, output ); |
151 | 151 | ||
152 | return output; | 152 | return output; |
153 | } | 153 | } |
154 | 154 | ||
155 | template <typename In, typename Out> | 155 | template <typename In, typename Out> |
156 | Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 156 | Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
157 | while ( begin < end ) { | 157 | while ( begin < end ) { |
158 | Uint32 codepoint; | 158 | Uint32 codepoint; |
159 | begin = Decode( begin, end, codepoint ); | 159 | begin = Decode( begin, end, codepoint ); |
160 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | 160 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); |
161 | } | 161 | } |
162 | 162 | ||
163 | return output; | 163 | return output; |
164 | } | 164 | } |
165 | 165 | ||
166 | #ifndef EFSW_NO_WIDECHAR | 166 | #ifndef EFSW_NO_WIDECHAR |
167 | template <typename In, typename Out> | 167 | template <typename In, typename Out> |
168 | Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 168 | Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
169 | while ( begin < end ) { | 169 | while ( begin < end ) { |
170 | Uint32 codepoint; | 170 | Uint32 codepoint; |
171 | begin = Decode( begin, end, codepoint ); | 171 | begin = Decode( begin, end, codepoint ); |
172 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | 172 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); |
173 | } | 173 | } |
174 | 174 | ||
175 | return output; | 175 | return output; |
176 | } | 176 | } |
177 | #endif | 177 | #endif |
178 | 178 | ||
179 | template <typename In, typename Out> | 179 | template <typename In, typename Out> |
180 | Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { | 180 | Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { |
181 | // Latin-1 is directly compatible with Unicode encodings, | 181 | // Latin-1 is directly compatible with Unicode encodings, |
182 | // and can thus be treated as (a sub-range of) UTF-32 | 182 | // and can thus be treated as (a sub-range of) UTF-32 |
183 | while ( begin < end ) { | 183 | while ( begin < end ) { |
184 | Uint32 codepoint; | 184 | Uint32 codepoint; |
185 | begin = Decode( begin, end, codepoint ); | 185 | begin = Decode( begin, end, codepoint ); |
186 | *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; | 186 | *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; |
187 | } | 187 | } |
188 | 188 | ||
189 | return output; | 189 | return output; |
190 | } | 190 | } |
191 | 191 | ||
192 | template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { | 192 | template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { |
193 | while ( begin < end ) | 193 | while ( begin < end ) |
194 | *output++ = *begin++; | 194 | *output++ = *begin++; |
195 | 195 | ||
196 | return output; | 196 | return output; |
197 | } | 197 | } |
198 | 198 | ||
199 | template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { | 199 | template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { |
200 | while ( begin < end ) { | 200 | while ( begin < end ) { |
201 | Uint32 codepoint; | 201 | Uint32 codepoint; |
202 | begin = Decode( begin, end, codepoint ); | 202 | begin = Decode( begin, end, codepoint ); |
203 | output = Utf<16>::Encode( codepoint, output ); | 203 | output = Utf<16>::Encode( codepoint, output ); |
204 | } | 204 | } |
205 | 205 | ||
206 | return output; | 206 | return output; |
207 | } | 207 | } |
208 | 208 | ||
209 | template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { | 209 | template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { |
210 | while ( begin < end ) { | 210 | while ( begin < end ) { |
211 | Uint32 codepoint; | 211 | Uint32 codepoint; |
212 | begin = Decode( begin, end, codepoint ); | 212 | begin = Decode( begin, end, codepoint ); |
213 | *output++ = codepoint; | 213 | *output++ = codepoint; |
214 | } | 214 | } |
215 | 215 | ||
216 | return output; | 216 | return output; |
217 | } | 217 | } |
218 | 218 | ||
219 | template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | 219 | template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { |
220 | Uint16 first = *begin++; | 220 | Uint16 first = *begin++; |
221 | 221 | ||
222 | // If it's a surrogate pair, first convert to a single UTF-32 character | 222 | // If it's a surrogate pair, first convert to a single UTF-32 character |
223 | if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { | 223 | if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { |
224 | if ( begin < end ) { | 224 | if ( begin < end ) { |
225 | Uint32 second = *begin++; | 225 | Uint32 second = *begin++; |
226 | if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { | 226 | if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { |
227 | // The second element is valid: convert the two elements to a UTF-32 character | 227 | // The second element is valid: convert the two elements to a UTF-32 character |
228 | output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + | 228 | output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + |
229 | 0x0010000 ); | 229 | 0x0010000 ); |
230 | } else { | 230 | } else { |
231 | // Invalid character | 231 | // Invalid character |
232 | output = replacement; | 232 | output = replacement; |
233 | } | 233 | } |
234 | } else { | 234 | } else { |
235 | // Invalid character | 235 | // Invalid character |
236 | begin = end; | 236 | begin = end; |
237 | output = replacement; | 237 | output = replacement; |
238 | } | 238 | } |
239 | } else { | 239 | } else { |
240 | // We can make a direct copy | 240 | // We can make a direct copy |
241 | output = first; | 241 | output = first; |
242 | } | 242 | } |
243 | 243 | ||
244 | return begin; | 244 | return begin; |
245 | } | 245 | } |
246 | 246 | ||
247 | template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { | 247 | template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { |
248 | if ( input < 0xFFFF ) { | 248 | if ( input < 0xFFFF ) { |
249 | // The character can be copied directly, we just need to check if it's in the valid range | 249 | // The character can be copied directly, we just need to check if it's in the valid range |
250 | if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { | 250 | if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { |
251 | // Invalid character (this range is reserved) | 251 | // Invalid character (this range is reserved) |
252 | if ( replacement ) | 252 | if ( replacement ) |
253 | *output++ = replacement; | 253 | *output++ = replacement; |
254 | } else { | 254 | } else { |
255 | // Valid character directly convertible to a single UTF-16 character | 255 | // Valid character directly convertible to a single UTF-16 character |
256 | *output++ = static_cast<Uint16>( input ); | 256 | *output++ = static_cast<Uint16>( input ); |
257 | } | 257 | } |
258 | } else if ( input > 0x0010FFFF ) { | 258 | } else if ( input > 0x0010FFFF ) { |
259 | // Invalid character (greater than the maximum unicode value) | 259 | // Invalid character (greater than the maximum unicode value) |
260 | if ( replacement ) | 260 | if ( replacement ) |
261 | *output++ = replacement; | 261 | *output++ = replacement; |
262 | } else { | 262 | } else { |
263 | // The input character will be converted to two UTF-16 elements | 263 | // The input character will be converted to two UTF-16 elements |
264 | input -= 0x0010000; | 264 | input -= 0x0010000; |
265 | *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); | 265 | *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); |
266 | *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); | 266 | *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); |
267 | } | 267 | } |
268 | 268 | ||
269 | return output; | 269 | return output; |
270 | } | 270 | } |
271 | 271 | ||
272 | template <typename In> In Utf<16>::Next( In begin, In end ) { | 272 | template <typename In> In Utf<16>::Next( In begin, In end ) { |
273 | Uint32 codepoint; | 273 | Uint32 codepoint; |
274 | return Decode( begin, end, codepoint ); | 274 | return Decode( begin, end, codepoint ); |
275 | } | 275 | } |
276 | 276 | ||
277 | template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { | 277 | template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { |
278 | std::size_t length = 0; | 278 | std::size_t length = 0; |
279 | while ( begin < end ) { | 279 | while ( begin < end ) { |
280 | begin = Next( begin, end ); | 280 | begin = Next( begin, end ); |
281 | ++length; | 281 | ++length; |
282 | } | 282 | } |
283 | 283 | ||
284 | return length; | 284 | return length; |
285 | } | 285 | } |
286 | 286 | ||
287 | template <typename In, typename Out> | 287 | template <typename In, typename Out> |
288 | Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 288 | Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
289 | while ( begin < end ) { | 289 | while ( begin < end ) { |
290 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | 290 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); |
291 | output = Encode( codepoint, output ); | 291 | output = Encode( codepoint, output ); |
292 | } | 292 | } |
293 | 293 | ||
294 | return output; | 294 | return output; |
295 | } | 295 | } |
296 | 296 | ||
297 | template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { | 297 | template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { |
298 | while ( begin < end ) { | 298 | while ( begin < end ) { |
299 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | 299 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); |
300 | output = Encode( codepoint, output ); | 300 | output = Encode( codepoint, output ); |
301 | } | 301 | } |
302 | 302 | ||
303 | return output; | 303 | return output; |
304 | } | 304 | } |
305 | 305 | ||
306 | template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { | 306 | template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { |
307 | // Latin-1 is directly compatible with Unicode encodings, | 307 | // Latin-1 is directly compatible with Unicode encodings, |
308 | // and can thus be treated as (a sub-range of) UTF-32 | 308 | // and can thus be treated as (a sub-range of) UTF-32 |
309 | while ( begin < end ) | 309 | while ( begin < end ) |
310 | *output++ = *begin++; | 310 | *output++ = *begin++; |
311 | 311 | ||
312 | return output; | 312 | return output; |
313 | } | 313 | } |
314 | 314 | ||
315 | template <typename In, typename Out> | 315 | template <typename In, typename Out> |
316 | Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 316 | Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
317 | while ( begin < end ) { | 317 | while ( begin < end ) { |
318 | Uint32 codepoint; | 318 | Uint32 codepoint; |
319 | begin = Decode( begin, end, codepoint ); | 319 | begin = Decode( begin, end, codepoint ); |
320 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | 320 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); |
321 | } | 321 | } |
322 | 322 | ||
323 | return output; | 323 | return output; |
324 | } | 324 | } |
325 | 325 | ||
326 | #ifndef EFSW_NO_WIDECHAR | 326 | #ifndef EFSW_NO_WIDECHAR |
327 | template <typename In, typename Out> | 327 | template <typename In, typename Out> |
328 | Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 328 | Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
329 | while ( begin < end ) { | 329 | while ( begin < end ) { |
330 | Uint32 codepoint; | 330 | Uint32 codepoint; |
331 | begin = Decode( begin, end, codepoint ); | 331 | begin = Decode( begin, end, codepoint ); |
332 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | 332 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); |
333 | } | 333 | } |
334 | 334 | ||
335 | return output; | 335 | return output; |
336 | } | 336 | } |
337 | #endif | 337 | #endif |
338 | 338 | ||
339 | template <typename In, typename Out> | 339 | template <typename In, typename Out> |
340 | Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { | 340 | Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { |
341 | // Latin-1 is directly compatible with Unicode encodings, | 341 | // Latin-1 is directly compatible with Unicode encodings, |
342 | // and can thus be treated as (a sub-range of) UTF-32 | 342 | // and can thus be treated as (a sub-range of) UTF-32 |
343 | while ( begin < end ) { | 343 | while ( begin < end ) { |
344 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | 344 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; |
345 | begin++; | 345 | begin++; |
346 | } | 346 | } |
347 | 347 | ||
348 | return output; | 348 | return output; |
349 | } | 349 | } |
350 | 350 | ||
351 | template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { | 351 | template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { |
352 | while ( begin < end ) { | 352 | while ( begin < end ) { |
353 | Uint32 codepoint; | 353 | Uint32 codepoint; |
354 | begin = Decode( begin, end, codepoint ); | 354 | begin = Decode( begin, end, codepoint ); |
355 | output = Utf<8>::Encode( codepoint, output ); | 355 | output = Utf<8>::Encode( codepoint, output ); |
356 | } | 356 | } |
357 | 357 | ||
358 | return output; | 358 | return output; |
359 | } | 359 | } |
360 | 360 | ||
361 | template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { | 361 | template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { |
362 | while ( begin < end ) | 362 | while ( begin < end ) |
363 | *output++ = *begin++; | 363 | *output++ = *begin++; |
364 | 364 | ||
365 | return output; | 365 | return output; |
366 | } | 366 | } |
367 | 367 | ||
368 | template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { | 368 | template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { |
369 | while ( begin < end ) { | 369 | while ( begin < end ) { |
370 | Uint32 codepoint; | 370 | Uint32 codepoint; |
371 | begin = Decode( begin, end, codepoint ); | 371 | begin = Decode( begin, end, codepoint ); |
372 | *output++ = codepoint; | 372 | *output++ = codepoint; |
373 | } | 373 | } |
374 | 374 | ||
375 | return output; | 375 | return output; |
376 | } | 376 | } |
377 | 377 | ||
378 | template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) { | 378 | template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) { |
379 | output = *begin++; | 379 | output = *begin++; |
380 | return begin; | 380 | return begin; |
381 | } | 381 | } |
382 | 382 | ||
383 | template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) { | 383 | template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) { |
384 | *output++ = input; | 384 | *output++ = input; |
385 | return output; | 385 | return output; |
386 | } | 386 | } |
387 | 387 | ||
388 | template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) { | 388 | template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) { |
389 | return ++begin; | 389 | return ++begin; |
390 | } | 390 | } |
391 | 391 | ||
392 | template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { | 392 | template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { |
393 | return begin - end; | 393 | return begin - end; |
394 | } | 394 | } |
395 | 395 | ||
396 | template <typename In, typename Out> | 396 | template <typename In, typename Out> |
397 | Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 397 | Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
398 | while ( begin < end ) | 398 | while ( begin < end ) |
399 | *output++ = DecodeAnsi( *begin++, locale ); | 399 | *output++ = DecodeAnsi( *begin++, locale ); |
400 | 400 | ||
401 | return output; | 401 | return output; |
402 | } | 402 | } |
403 | 403 | ||
404 | template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { | 404 | template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { |
405 | while ( begin < end ) | 405 | while ( begin < end ) |
406 | *output++ = DecodeWide( *begin++ ); | 406 | *output++ = DecodeWide( *begin++ ); |
407 | 407 | ||
408 | return output; | 408 | return output; |
409 | } | 409 | } |
410 | 410 | ||
411 | template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { | 411 | template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { |
412 | // Latin-1 is directly compatible with Unicode encodings, | 412 | // Latin-1 is directly compatible with Unicode encodings, |
413 | // and can thus be treated as (a sub-range of) UTF-32 | 413 | // and can thus be treated as (a sub-range of) UTF-32 |
414 | while ( begin < end ) | 414 | while ( begin < end ) |
415 | *output++ = *begin++; | 415 | *output++ = *begin++; |
416 | 416 | ||
417 | return output; | 417 | return output; |
418 | } | 418 | } |
419 | 419 | ||
420 | template <typename In, typename Out> | 420 | template <typename In, typename Out> |
421 | Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 421 | Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
422 | while ( begin < end ) | 422 | while ( begin < end ) |
423 | output = EncodeAnsi( *begin++, output, replacement, locale ); | 423 | output = EncodeAnsi( *begin++, output, replacement, locale ); |
424 | 424 | ||
425 | return output; | 425 | return output; |
426 | } | 426 | } |
427 | 427 | ||
428 | #ifndef EFSW_NO_WIDECHAR | 428 | #ifndef EFSW_NO_WIDECHAR |
429 | template <typename In, typename Out> | 429 | template <typename In, typename Out> |
430 | Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 430 | Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
431 | while ( begin < end ) | 431 | while ( begin < end ) |
432 | output = EncodeWide( *begin++, output, replacement ); | 432 | output = EncodeWide( *begin++, output, replacement ); |
433 | 433 | ||
434 | return output; | 434 | return output; |
435 | } | 435 | } |
436 | #endif | 436 | #endif |
437 | 437 | ||
438 | template <typename In, typename Out> | 438 | template <typename In, typename Out> |
439 | Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { | 439 | Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { |
440 | // Latin-1 is directly compatible with Unicode encodings, | 440 | // Latin-1 is directly compatible with Unicode encodings, |
441 | // and can thus be treated as (a sub-range of) UTF-32 | 441 | // and can thus be treated as (a sub-range of) UTF-32 |
442 | while ( begin < end ) { | 442 | while ( begin < end ) { |
443 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | 443 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; |
444 | begin++; | 444 | begin++; |
445 | } | 445 | } |
446 | 446 | ||
447 | return output; | 447 | return output; |
448 | } | 448 | } |
449 | 449 | ||
450 | template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { | 450 | template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { |
451 | while ( begin < end ) | 451 | while ( begin < end ) |
452 | output = Utf<8>::Encode( *begin++, output ); | 452 | output = Utf<8>::Encode( *begin++, output ); |
453 | 453 | ||
454 | return output; | 454 | return output; |
455 | } | 455 | } |
456 | 456 | ||
457 | template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { | 457 | template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { |
458 | while ( begin < end ) | 458 | while ( begin < end ) |
459 | output = Utf<16>::Encode( *begin++, output ); | 459 | output = Utf<16>::Encode( *begin++, output ); |
460 | 460 | ||
461 | return output; | 461 | return output; |
462 | } | 462 | } |
463 | 463 | ||
464 | template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { | 464 | template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { |
465 | while ( begin < end ) | 465 | while ( begin < end ) |
466 | *output++ = *begin++; | 466 | *output++ = *begin++; |
467 | 467 | ||
468 | return output; | 468 | return output; |
469 | } | 469 | } |
470 | 470 | ||
471 | template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { | 471 | template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { |
472 | // On Windows, gcc's standard library (glibc++) has almost | 472 | // On Windows, gcc's standard library (glibc++) has almost |
473 | // no support for Unicode stuff. As a consequence, in this | 473 | // no support for Unicode stuff. As a consequence, in this |
474 | // context we can only use the default locale and ignore | 474 | // context we can only use the default locale and ignore |
475 | // the one passed as parameter. | 475 | // the one passed as parameter. |
476 | 476 | ||
477 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | 477 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ |
478 | ( defined( __GLIBCPP__ ) || \ | 478 | ( defined( __GLIBCPP__ ) || \ |
479 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | 479 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ |
480 | !( defined( __SGI_STL_PORT ) || \ | 480 | !( defined( __SGI_STL_PORT ) || \ |
481 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | 481 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ |
482 | 482 | ||
483 | wchar_t character = 0; | 483 | wchar_t character = 0; |
484 | mbtowc( &character, &input, 1 ); | 484 | mbtowc( &character, &input, 1 ); |
485 | return static_cast<Uint32>( character ); | 485 | return static_cast<Uint32>( character ); |
486 | 486 | ||
487 | #else | 487 | #else |
488 | // Get the facet of the locale which deals with character conversion | 488 | // Get the facet of the locale which deals with character conversion |
489 | #ifndef EFSW_NO_WIDECHAR | 489 | #ifndef EFSW_NO_WIDECHAR |
490 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | 490 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); |
491 | #else | 491 | #else |
492 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | 492 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); |
493 | #endif | 493 | #endif |
494 | 494 | ||
495 | // Use the facet to convert each character of the input string | 495 | // Use the facet to convert each character of the input string |
496 | return static_cast<Uint32>( facet.widen( input ) ); | 496 | return static_cast<Uint32>( facet.widen( input ) ); |
497 | 497 | ||
498 | #endif | 498 | #endif |
499 | } | 499 | } |
500 | 500 | ||
501 | template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { | 501 | template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { |
502 | // The encoding of wide characters is not well defined and is left to the system; | 502 | // The encoding of wide characters is not well defined and is left to the system; |
503 | // however we can safely assume that it is UCS-2 on Windows and | 503 | // however we can safely assume that it is UCS-2 on Windows and |
504 | // UCS-4 on Unix systems. | 504 | // UCS-4 on Unix systems. |
505 | // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, | 505 | // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, |
506 | // and UCS-4 *is* UTF-32). | 506 | // and UCS-4 *is* UTF-32). |
507 | 507 | ||
508 | return input; | 508 | return input; |
509 | } | 509 | } |
510 | 510 | ||
511 | template <typename Out> | 511 | template <typename Out> |
512 | Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, | 512 | Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, |
513 | const std::locale& locale ) { | 513 | const std::locale& locale ) { |
514 | // On Windows, gcc's standard library (glibc++) has almost | 514 | // On Windows, gcc's standard library (glibc++) has almost |
515 | // no support for Unicode stuff. As a consequence, in this | 515 | // no support for Unicode stuff. As a consequence, in this |
516 | // context we can only use the default locale and ignore | 516 | // context we can only use the default locale and ignore |
517 | // the one passed as parameter. | 517 | // the one passed as parameter. |
518 | 518 | ||
519 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | 519 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ |
520 | ( defined( __GLIBCPP__ ) || \ | 520 | ( defined( __GLIBCPP__ ) || \ |
521 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | 521 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ |
522 | !( defined( __SGI_STL_PORT ) || \ | 522 | !( defined( __SGI_STL_PORT ) || \ |
523 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | 523 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ |
524 | 524 | ||
525 | char character = 0; | 525 | char character = 0; |
526 | if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) | 526 | if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) |
527 | *output++ = character; | 527 | *output++ = character; |
528 | else if ( replacement ) | 528 | else if ( replacement ) |
529 | *output++ = replacement; | 529 | *output++ = replacement; |
530 | 530 | ||
531 | return output; | 531 | return output; |
532 | 532 | ||
533 | #else | 533 | #else |
534 | // Get the facet of the locale which deals with character conversion | 534 | // Get the facet of the locale which deals with character conversion |
535 | #ifndef EFSW_NO_WIDECHAR | 535 | #ifndef EFSW_NO_WIDECHAR |
536 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | 536 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); |
537 | #else | 537 | #else |
538 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | 538 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); |
539 | #endif | 539 | #endif |
540 | 540 | ||
541 | // Use the facet to convert each character of the input string | 541 | // Use the facet to convert each character of the input string |
542 | *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); | 542 | *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); |
543 | 543 | ||
544 | return output; | 544 | return output; |
545 | 545 | ||
546 | #endif | 546 | #endif |
547 | } | 547 | } |
548 | 548 | ||
549 | #ifndef EFSW_NO_WIDECHAR | 549 | #ifndef EFSW_NO_WIDECHAR |
550 | template <typename Out> | 550 | template <typename Out> |
551 | Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { | 551 | Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { |
552 | // The encoding of wide characters is not well defined and is left to the system; | 552 | // The encoding of wide characters is not well defined and is left to the system; |
553 | // however we can safely assume that it is UCS-2 on Windows and | 553 | // however we can safely assume that it is UCS-2 on Windows and |
554 | // UCS-4 on Unix systems. | 554 | // UCS-4 on Unix systems. |
555 | // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). | 555 | // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). |
556 | // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). | 556 | // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). |
557 | 557 | ||
558 | switch ( sizeof( wchar_t ) ) { | 558 | switch ( sizeof( wchar_t ) ) { |
559 | case 4: { | 559 | case 4: { |
560 | *output++ = static_cast<wchar_t>( codepoint ); | 560 | *output++ = static_cast<wchar_t>( codepoint ); |
561 | break; | 561 | break; |
562 | } | 562 | } |
563 | 563 | ||
564 | default: { | 564 | default: { |
565 | if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { | 565 | if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { |
566 | *output++ = static_cast<wchar_t>( codepoint ); | 566 | *output++ = static_cast<wchar_t>( codepoint ); |
567 | } else if ( replacement ) { | 567 | } else if ( replacement ) { |
568 | *output++ = replacement; | 568 | *output++ = replacement; |
569 | } | 569 | } |
570 | break; | 570 | break; |
571 | } | 571 | } |
572 | } | 572 | } |
573 | 573 | ||
574 | return output; | 574 | return output; |
575 | } | 575 | } |
576 | #endif | 576 | #endif |
diff --git a/src/3rdParty/efsw/Watcher.cpp b/src/3rdParty/efsw/Watcher.cpp index 913ae3c..913ae3c 100755..100644 --- a/src/3rdParty/efsw/Watcher.cpp +++ b/src/3rdParty/efsw/Watcher.cpp | |||
diff --git a/src/3rdParty/efsw/Watcher.hpp b/src/3rdParty/efsw/Watcher.hpp index 84f0980..84f0980 100755..100644 --- a/src/3rdParty/efsw/Watcher.hpp +++ b/src/3rdParty/efsw/Watcher.hpp | |||
diff --git a/src/3rdParty/efsw/WatcherFSEvents.cpp b/src/3rdParty/efsw/WatcherFSEvents.cpp index b562d3c..f963374 100755..100644 --- a/src/3rdParty/efsw/WatcherFSEvents.cpp +++ b/src/3rdParty/efsw/WatcherFSEvents.cpp | |||
@@ -8,22 +8,11 @@ | |||
8 | namespace efsw { | 8 | namespace efsw { |
9 | 9 | ||
10 | WatcherFSEvents::WatcherFSEvents() : | 10 | WatcherFSEvents::WatcherFSEvents() : |
11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {} | 11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {} |
12 | |||
13 | WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, | ||
14 | bool recursive, WatcherFSEvents* /*parent*/ ) : | ||
15 | Watcher( id, directory, listener, recursive ), | ||
16 | FWatcher( NULL ), | ||
17 | FSStream( NULL ), | ||
18 | WatcherGen( NULL ), | ||
19 | initializedAsync( false ) {} | ||
20 | 12 | ||
21 | WatcherFSEvents::~WatcherFSEvents() { | 13 | WatcherFSEvents::~WatcherFSEvents() { |
22 | if ( NULL != FSStream ) { | 14 | if ( NULL != FSStream ) { |
23 | if ( initializedAsync ) { | 15 | FSEventStreamStop( FSStream ); |
24 | FSEventStreamStop( FSStream ); | ||
25 | } | ||
26 | |||
27 | FSEventStreamInvalidate( FSStream ); | 16 | FSEventStreamInvalidate( FSStream ); |
28 | FSEventStreamRelease( FSStream ); | 17 | FSEventStreamRelease( FSStream ); |
29 | } | 18 | } |
@@ -39,7 +28,9 @@ void WatcherFSEvents::init() { | |||
39 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; | 28 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; |
40 | 29 | ||
41 | if ( FileWatcherFSEvents::isGranular() ) { | 30 | if ( FileWatcherFSEvents::isGranular() ) { |
42 | streamFlags = efswFSEventStreamCreateFlagFileEvents; | 31 | streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer | |
32 | efswFSEventStreamCreateFlagUseExtendedData | | ||
33 | efswFSEventStreamCreateFlagUseCFTypes; | ||
43 | } else { | 34 | } else { |
44 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); | 35 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); |
45 | } | 36 | } |
@@ -52,49 +43,49 @@ void WatcherFSEvents::init() { | |||
52 | ctx.release = NULL; | 43 | ctx.release = NULL; |
53 | ctx.copyDescription = NULL; | 44 | ctx.copyDescription = NULL; |
54 | 45 | ||
46 | dispatch_queue_t queue = dispatch_queue_create( NULL, NULL ); | ||
47 | |||
55 | FSStream = | 48 | FSStream = |
56 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, | 49 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, |
57 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); | 50 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags ); |
58 | FWatcher.load()->mNeedInitMutex.lock(); | ||
59 | FWatcher.load()->mNeedInit.push_back( this ); | ||
60 | FWatcher.load()->mNeedInitMutex.unlock(); | ||
61 | 51 | ||
62 | CFRelease( CFDirectoryArray ); | 52 | FSEventStreamSetDispatchQueue( FSStream, queue ); |
63 | CFRelease( CFDirectory ); | ||
64 | } | ||
65 | 53 | ||
66 | void WatcherFSEvents::initAsync() { | ||
67 | FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(), | ||
68 | kCFRunLoopDefaultMode ); | ||
69 | FSEventStreamStart( FSStream ); | 54 | FSEventStreamStart( FSStream ); |
70 | initializedAsync = true; | 55 | |
56 | CFRelease( CFDirectoryArray ); | ||
57 | CFRelease( CFDirectory ); | ||
71 | } | 58 | } |
72 | 59 | ||
73 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, | 60 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, |
74 | const std::string& filename, Action action, | 61 | const std::string& filename, Action action, |
75 | std::string oldFilename ) { | 62 | std::string oldFilename ) { |
76 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), | 63 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), |
77 | FileSystem::precomposeFileName( filename ), action, oldFilename ); | 64 | FileSystem::precomposeFileName( filename ), action, |
65 | FileSystem::precomposeFileName( oldFilename ) ); | ||
78 | } | 66 | } |
79 | 67 | ||
80 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, | 68 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, |
81 | std::string& dirPath, std::string& filePath ) { | 69 | std::string& dirPath, std::string& filePath, Uint64 inode ) { |
82 | if ( flags & efswFSEventStreamEventFlagItemCreated ) { | 70 | if ( ( flags & efswFSEventStreamEventFlagItemCreated ) && FileInfo::exists( path ) && |
83 | if ( FileInfo::exists( path ) ) { | 71 | ( !SanitizeEvents || FilesAdded.find( inode ) != FilesAdded.end() ) ) { |
84 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | 72 | sendFileAction( ID, dirPath, filePath, Actions::Add ); |
85 | } | 73 | |
74 | if ( SanitizeEvents ) | ||
75 | FilesAdded.insert( inode ); | ||
86 | } | 76 | } |
87 | 77 | ||
88 | if ( flags & efswFSEventsModified ) { | 78 | if ( flags & ModifiedFlags ) { |
89 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | 79 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); |
90 | } | 80 | } |
91 | 81 | ||
92 | if ( flags & efswFSEventStreamEventFlagItemRemoved ) { | 82 | if ( ( flags & efswFSEventStreamEventFlagItemRemoved ) && !FileInfo::exists( path ) ) { |
93 | // Since i don't know the order, at least i try to keep the data consistent with the real | 83 | // Since i don't know the order, at least i try to keep the data consistent with the real |
94 | // state | 84 | // state |
95 | if ( !FileInfo::exists( path ) ) { | 85 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
96 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 86 | |
97 | } | 87 | if ( SanitizeEvents ) |
88 | FilesAdded.erase( inode ); | ||
98 | } | 89 | } |
99 | } | 90 | } |
100 | 91 | ||
@@ -136,19 +127,20 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
136 | // been added modified and erased, but i can't know if first was erased and then added | 127 | // been added modified and erased, but i can't know if first was erased and then added |
137 | // and modified, or added, then modified and then erased. I don't know what they were | 128 | // and modified, or added, then modified and then erased. I don't know what they were |
138 | // thinking by doing this... | 129 | // thinking by doing this... |
139 | efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags ); | 130 | efDEBUG( "Event in: %s - flags: 0x%x\n", event.Path.c_str(), event.Flags ); |
140 | 131 | ||
141 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { | 132 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { |
142 | if ( ( i + 1 < esize ) && | 133 | if ( ( i + 1 < esize ) && |
143 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && | 134 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && |
144 | ( events[i + 1].Id == event.Id + 1 ) ) { | 135 | ( events[i + 1].inode == event.inode ) ) { |
145 | FSEvent& nEvent = events[i + 1]; | 136 | FSEvent& nEvent = events[i + 1]; |
146 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); | 137 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); |
147 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); | 138 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); |
148 | 139 | ||
149 | if ( event.Path != nEvent.Path ) { | 140 | if ( event.Path != nEvent.Path ) { |
150 | if ( dirPath == newDir ) { | 141 | if ( dirPath == newDir ) { |
151 | if ( !FileInfo::exists( event.Path ) ) { | 142 | if ( !FileInfo::exists( event.Path ) || |
143 | 0 == strcasecmp( event.Path.c_str(), nEvent.Path.c_str() ) ) { | ||
152 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, | 144 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, |
153 | filePath ); | 145 | filePath ); |
154 | } else { | 146 | } else { |
@@ -159,12 +151,12 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
159 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 151 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
160 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); | 152 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); |
161 | 153 | ||
162 | if ( nEvent.Flags & efswFSEventsModified ) { | 154 | if ( nEvent.Flags & ModifiedFlags ) { |
163 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); | 155 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); |
164 | } | 156 | } |
165 | } | 157 | } |
166 | } else { | 158 | } else { |
167 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); | 159 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath, event.inode ); |
168 | } | 160 | } |
169 | 161 | ||
170 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | | 162 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | |
@@ -180,14 +172,14 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
180 | } else if ( FileInfo::exists( event.Path ) ) { | 172 | } else if ( FileInfo::exists( event.Path ) ) { |
181 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | 173 | sendFileAction( ID, dirPath, filePath, Actions::Add ); |
182 | 174 | ||
183 | if ( event.Flags & efswFSEventsModified ) { | 175 | if ( event.Flags & ModifiedFlags ) { |
184 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | 176 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); |
185 | } | 177 | } |
186 | } else { | 178 | } else { |
187 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 179 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
188 | } | 180 | } |
189 | } else { | 181 | } else { |
190 | handleAddModDel( event.Flags, event.Path, dirPath, filePath ); | 182 | handleAddModDel( event.Flags, event.Path, dirPath, filePath, event.inode ); |
191 | } | 183 | } |
192 | } else { | 184 | } else { |
193 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); | 185 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); |
@@ -197,7 +189,7 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
197 | } | 189 | } |
198 | 190 | ||
199 | void WatcherFSEvents::process() { | 191 | void WatcherFSEvents::process() { |
200 | std::set<std::string>::iterator it = DirsChanged.begin(); | 192 | std::unordered_set<std::string>::iterator it = DirsChanged.begin(); |
201 | 193 | ||
202 | for ( ; it != DirsChanged.end(); it++ ) { | 194 | for ( ; it != DirsChanged.end(); it++ ) { |
203 | if ( !FileWatcherFSEvents::isGranular() ) { | 195 | if ( !FileWatcherFSEvents::isGranular() ) { |
diff --git a/src/3rdParty/efsw/WatcherFSEvents.hpp b/src/3rdParty/efsw/WatcherFSEvents.hpp index 4dbb231..f05b094 100755..100644 --- a/src/3rdParty/efsw/WatcherFSEvents.hpp +++ b/src/3rdParty/efsw/WatcherFSEvents.hpp | |||
@@ -9,51 +9,72 @@ | |||
9 | #include <CoreServices/CoreServices.h> | 9 | #include <CoreServices/CoreServices.h> |
10 | #include <efsw/FileInfo.hpp> | 10 | #include <efsw/FileInfo.hpp> |
11 | #include <efsw/WatcherGeneric.hpp> | 11 | #include <efsw/WatcherGeneric.hpp> |
12 | #include <set> | 12 | #include <unordered_set> |
13 | #include <vector> | 13 | #include <vector> |
14 | 14 | ||
15 | namespace efsw { | 15 | namespace efsw { |
16 | 16 | ||
17 | /* OSX < 10.7 has no file events */ | ||
18 | /* So i declare the events constants */ | ||
19 | enum FSEventEvents { | ||
20 | efswFSEventStreamCreateFlagUseCFTypes = 0x00000001, | ||
21 | efswFSEventStreamCreateFlagNoDefer = 0x00000002, | ||
22 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, | ||
23 | efswFSEventStreamCreateFlagUseExtendedData = 0x00000040, | ||
24 | efswFSEventStreamEventFlagItemCreated = 0x00000100, | ||
25 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, | ||
26 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | ||
27 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, | ||
28 | efswFSEventStreamEventFlagItemModified = 0x00001000, | ||
29 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | ||
30 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, | ||
31 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, | ||
32 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, | ||
33 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, | ||
34 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, | ||
35 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | | ||
36 | efswFSEventStreamEventFlagItemModified | | ||
37 | efswFSEventStreamEventFlagItemInodeMetaMod | ||
38 | }; | ||
39 | |||
17 | class FileWatcherFSEvents; | 40 | class FileWatcherFSEvents; |
18 | 41 | ||
19 | class FSEvent { | 42 | class FSEvent { |
20 | public: | 43 | public: |
21 | FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {} | 44 | FSEvent( std::string path, long flags, Uint64 id, Uint64 inode = 0 ) : |
45 | Path( path ), Flags( flags ), Id( id ), inode( inode ) {} | ||
22 | 46 | ||
23 | std::string Path; | 47 | std::string Path; |
24 | long Flags; | 48 | long Flags{ 0 }; |
25 | Uint64 Id; | 49 | Uint64 Id{ 0 }; |
50 | Uint64 inode{ 0 }; | ||
26 | }; | 51 | }; |
27 | 52 | ||
28 | class WatcherFSEvents : public Watcher { | 53 | class WatcherFSEvents : public Watcher { |
29 | public: | 54 | public: |
30 | WatcherFSEvents(); | 55 | WatcherFSEvents(); |
31 | 56 | ||
32 | WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
33 | WatcherFSEvents* parent = NULL ); | ||
34 | |||
35 | ~WatcherFSEvents(); | 57 | ~WatcherFSEvents(); |
36 | 58 | ||
37 | void init(); | 59 | void init(); |
38 | 60 | ||
39 | void initAsync(); | ||
40 | |||
41 | void handleActions( std::vector<FSEvent>& events ); | 61 | void handleActions( std::vector<FSEvent>& events ); |
42 | 62 | ||
43 | void process(); | 63 | void process(); |
44 | 64 | ||
45 | Atomic<FileWatcherFSEvents*> FWatcher; | 65 | Atomic<FileWatcherFSEvents*> FWatcher; |
46 | FSEventStreamRef FSStream; | 66 | FSEventStreamRef FSStream; |
67 | Uint64 ModifiedFlags{ efswFSEventsModified }; | ||
68 | bool SanitizeEvents{ false }; | ||
47 | 69 | ||
48 | protected: | 70 | protected: |
49 | void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, | 71 | void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, |
50 | std::string& filePath ); | 72 | std::string& filePath, Uint64 inode ); |
51 | 73 | ||
52 | WatcherGeneric* WatcherGen; | 74 | WatcherGeneric* WatcherGen; |
53 | 75 | ||
54 | Atomic<bool> initializedAsync; | 76 | std::unordered_set<std::string> DirsChanged; |
55 | 77 | std::unordered_set<Uint64> FilesAdded; | |
56 | std::set<std::string> DirsChanged; | ||
57 | 78 | ||
58 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, | 79 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, |
59 | Action action, std::string oldFilename = "" ); | 80 | Action action, std::string oldFilename = "" ); |
diff --git a/src/3rdParty/efsw/WatcherGeneric.cpp b/src/3rdParty/efsw/WatcherGeneric.cpp index a6bb106..a6bb106 100755..100644 --- a/src/3rdParty/efsw/WatcherGeneric.cpp +++ b/src/3rdParty/efsw/WatcherGeneric.cpp | |||
diff --git a/src/3rdParty/efsw/WatcherGeneric.hpp b/src/3rdParty/efsw/WatcherGeneric.hpp index 9cf8365..d11ec20 100755..100644 --- a/src/3rdParty/efsw/WatcherGeneric.hpp +++ b/src/3rdParty/efsw/WatcherGeneric.hpp | |||
@@ -17,7 +17,7 @@ class WatcherGeneric : public Watcher { | |||
17 | 17 | ||
18 | ~WatcherGeneric(); | 18 | ~WatcherGeneric(); |
19 | 19 | ||
20 | void watch(); | 20 | void watch() override; |
21 | 21 | ||
22 | void watchDir( std::string dir ); | 22 | void watchDir( std::string dir ); |
23 | 23 | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.cpp b/src/3rdParty/efsw/WatcherInotify.cpp index 7259bb1..812ddae 100755..100644 --- a/src/3rdParty/efsw/WatcherInotify.cpp +++ b/src/3rdParty/efsw/WatcherInotify.cpp | |||
@@ -4,10 +4,6 @@ namespace efsw { | |||
4 | 4 | ||
5 | WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} | 5 | WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} |
6 | 6 | ||
7 | WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, | ||
8 | bool recursive, WatcherInotify* parent ) : | ||
9 | Watcher( id, directory, listener, recursive ), Parent( parent ), DirInfo( directory ) {} | ||
10 | |||
11 | bool WatcherInotify::inParentTree( WatcherInotify* parent ) { | 7 | bool WatcherInotify::inParentTree( WatcherInotify* parent ) { |
12 | WatcherInotify* tNext = Parent; | 8 | WatcherInotify* tNext = Parent; |
13 | 9 | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.hpp b/src/3rdParty/efsw/WatcherInotify.hpp index bf2ff5e..ec55ed0 100755..100644 --- a/src/3rdParty/efsw/WatcherInotify.hpp +++ b/src/3rdParty/efsw/WatcherInotify.hpp | |||
@@ -10,15 +10,13 @@ class WatcherInotify : public Watcher { | |||
10 | public: | 10 | public: |
11 | WatcherInotify(); | 11 | WatcherInotify(); |
12 | 12 | ||
13 | WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
14 | WatcherInotify* parent = NULL ); | ||
15 | |||
16 | bool inParentTree( WatcherInotify* parent ); | 13 | bool inParentTree( WatcherInotify* parent ); |
17 | 14 | ||
18 | WatcherInotify* Parent; | 15 | WatcherInotify* Parent; |
19 | WatchID InotifyID; | 16 | WatchID InotifyID; |
20 | 17 | ||
21 | FileInfo DirInfo; | 18 | FileInfo DirInfo; |
19 | bool syntheticEvents{ false }; | ||
22 | }; | 20 | }; |
23 | 21 | ||
24 | } // namespace efsw | 22 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/WatcherKqueue.cpp b/src/3rdParty/efsw/WatcherKqueue.cpp index 441948a..424b989 100755..100644 --- a/src/3rdParty/efsw/WatcherKqueue.cpp +++ b/src/3rdParty/efsw/WatcherKqueue.cpp | |||
@@ -139,7 +139,7 @@ void WatcherKqueue::addAll() { | |||
139 | void WatcherKqueue::removeAll() { | 139 | void WatcherKqueue::removeAll() { |
140 | efDEBUG( "removeAll(): Removing all child watchers\n" ); | 140 | efDEBUG( "removeAll(): Removing all child watchers\n" ); |
141 | 141 | ||
142 | std::list<WatchID> erase; | 142 | std::vector<WatchID> erase; |
143 | 143 | ||
144 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { | 144 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { |
145 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); | 145 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); |
@@ -147,7 +147,7 @@ void WatcherKqueue::removeAll() { | |||
147 | erase.push_back( it->second->ID ); | 147 | erase.push_back( it->second->ID ); |
148 | } | 148 | } |
149 | 149 | ||
150 | for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { | 150 | for ( std::vector<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { |
151 | removeWatch( *eit ); | 151 | removeWatch( *eit ); |
152 | } | 152 | } |
153 | } | 153 | } |
@@ -354,7 +354,8 @@ void WatcherKqueue::watch() { | |||
354 | bool needScan = false; | 354 | bool needScan = false; |
355 | 355 | ||
356 | // Then we get the the events of the current folder | 356 | // Then we get the the events of the current folder |
357 | while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, | 357 | while ( !mChangeList.empty() && |
358 | ( nev = kevent( mKqueue, mChangeList.data(), mChangeListCount + 1, &event, 1, | ||
358 | &mWatcher->mTimeOut ) ) != 0 ) { | 359 | &mWatcher->mTimeOut ) ) != 0 ) { |
359 | // An error ocurred? | 360 | // An error ocurred? |
360 | if ( nev == -1 ) { | 361 | if ( nev == -1 ) { |
@@ -436,7 +437,6 @@ void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, boo | |||
436 | 437 | ||
437 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | 438 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, |
438 | bool recursive, WatcherKqueue* parent ) { | 439 | bool recursive, WatcherKqueue* parent ) { |
439 | static long s_fc = 0; | ||
440 | static bool s_ug = false; | 440 | static bool s_ug = false; |
441 | 441 | ||
442 | std::string dir( directory ); | 442 | std::string dir( directory ); |
@@ -478,8 +478,6 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener | |||
478 | 478 | ||
479 | watch->addAll(); | 479 | watch->addAll(); |
480 | 480 | ||
481 | s_fc++; | ||
482 | |||
483 | // if failed to open the directory... erase the watcher | 481 | // if failed to open the directory... erase the watcher |
484 | if ( !watch->initOK() ) { | 482 | if ( !watch->initOK() ) { |
485 | int le = watch->lastErrno(); | 483 | int le = watch->lastErrno(); |
@@ -502,9 +500,8 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener | |||
502 | } | 500 | } |
503 | } else { | 501 | } else { |
504 | if ( !s_ug ) { | 502 | if ( !s_ug ) { |
505 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders " | 503 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld.\n", |
506 | "added: %ld\n", | 504 | mWatcher->mFileDescriptorCount ); |
507 | mWatcher->mFileDescriptorCount, s_fc ); | ||
508 | s_ug = true; | 505 | s_ug = true; |
509 | } | 506 | } |
510 | 507 | ||
diff --git a/src/3rdParty/efsw/WatcherKqueue.hpp b/src/3rdParty/efsw/WatcherKqueue.hpp index 87d898c..75c0f62 100755..100644 --- a/src/3rdParty/efsw/WatcherKqueue.hpp +++ b/src/3rdParty/efsw/WatcherKqueue.hpp | |||
@@ -49,7 +49,7 @@ class WatcherKqueue : public Watcher { | |||
49 | 49 | ||
50 | WatchID watchingDirectory( std::string dir ); | 50 | WatchID watchingDirectory( std::string dir ); |
51 | 51 | ||
52 | void watch(); | 52 | void watch() override; |
53 | 53 | ||
54 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | 54 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
55 | WatcherKqueue* parent ); | 55 | WatcherKqueue* parent ); |
diff --git a/src/3rdParty/efsw/WatcherWin32.cpp b/src/3rdParty/efsw/WatcherWin32.cpp index 3e8bcc7..712419e 100755..100644 --- a/src/3rdParty/efsw/WatcherWin32.cpp +++ b/src/3rdParty/efsw/WatcherWin32.cpp | |||
@@ -1,34 +1,114 @@ | |||
1 | #include <efsw/Debug.hpp> | ||
1 | #include <efsw/String.hpp> | 2 | #include <efsw/String.hpp> |
2 | #include <efsw/WatcherWin32.hpp> | 3 | #include <efsw/WatcherWin32.hpp> |
3 | 4 | ||
4 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
5 | 6 | ||
7 | #include <algorithm> | ||
8 | |||
6 | namespace efsw { | 9 | namespace efsw { |
7 | 10 | ||
8 | /// Unpacks events and passes them to a user defined callback. | 11 | struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX { |
9 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { | 12 | DWORD NextEntryOffset; |
10 | if ( dwNumberOfBytesTransfered == 0 || NULL == lpOverlapped ) { | 13 | DWORD Action; |
11 | return; | 14 | LARGE_INTEGER CreationTime; |
15 | LARGE_INTEGER LastModificationTime; | ||
16 | LARGE_INTEGER LastChangeTime; | ||
17 | LARGE_INTEGER LastAccessTime; | ||
18 | LARGE_INTEGER AllocatedLength; | ||
19 | LARGE_INTEGER FileSize; | ||
20 | DWORD FileAttributes; | ||
21 | DWORD ReparsePointTag; | ||
22 | LARGE_INTEGER FileId; | ||
23 | LARGE_INTEGER ParentFileId; | ||
24 | DWORD FileNameLength; | ||
25 | WCHAR FileName[1]; | ||
26 | }; | ||
27 | |||
28 | typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX; | ||
29 | |||
30 | typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer, | ||
31 | DWORD nBufferLength, BOOL bWatchSubtree, | ||
32 | DWORD dwNotifyFilter, LPDWORD lpBytesReturned, | ||
33 | LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, | ||
34 | DWORD ReadDirectoryNotifyInformationClass ); | ||
35 | |||
36 | static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL; | ||
37 | |||
38 | #define EFSW_ReadDirectoryNotifyExtendedInformation 2 | ||
39 | |||
40 | static void initReadDirectoryChangesEx() { | ||
41 | static bool hasInit = false; | ||
42 | if ( !hasInit ) { | ||
43 | hasInit = true; | ||
44 | |||
45 | HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" ); | ||
46 | if ( !hModule ) | ||
47 | return; | ||
48 | |||
49 | pReadDirectoryChangesExW = | ||
50 | (EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" ); | ||
12 | } | 51 | } |
52 | } | ||
13 | 53 | ||
14 | char szFile[MAX_PATH]; | 54 | void WatchCallbackOld( WatcherWin32* pWatch ) { |
15 | PFILE_NOTIFY_INFORMATION pNotify; | 55 | PFILE_NOTIFY_INFORMATION pNotify; |
16 | WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; | ||
17 | WatcherWin32* pWatch = tWatch->Watch; | ||
18 | size_t offset = 0; | 56 | size_t offset = 0; |
19 | |||
20 | do { | 57 | do { |
21 | bool skip = false; | 58 | bool skip = false; |
22 | 59 | ||
23 | pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; | 60 | pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; |
24 | offset += pNotify->NextEntryOffset; | 61 | offset += pNotify->NextEntryOffset; |
62 | int count = | ||
63 | WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
64 | pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); | ||
65 | if ( count == 0 ) | ||
66 | continue; | ||
67 | |||
68 | std::string nfile( count, '\0' ); | ||
69 | |||
70 | count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
71 | pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, | ||
72 | NULL, NULL ); | ||
73 | |||
74 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { | ||
75 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); | ||
76 | |||
77 | if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && | ||
78 | pWatch->LastModifiedEvent.file.Size == fifile.Size && | ||
79 | pWatch->LastModifiedEvent.fileName == nfile ) { | ||
80 | skip = true; | ||
81 | } | ||
82 | |||
83 | pWatch->LastModifiedEvent.fileName = nfile; | ||
84 | pWatch->LastModifiedEvent.file = fifile; | ||
85 | } | ||
86 | |||
87 | if ( !skip ) { | ||
88 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); | ||
89 | } | ||
90 | } while ( pNotify->NextEntryOffset != 0 ); | ||
91 | } | ||
92 | |||
93 | void WatchCallbackEx( WatcherWin32* pWatch ) { | ||
94 | EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify; | ||
95 | size_t offset = 0; | ||
96 | do { | ||
97 | bool skip = false; | ||
98 | |||
99 | pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset]; | ||
100 | offset += pNotify->NextEntryOffset; | ||
101 | int count = | ||
102 | WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
103 | pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); | ||
104 | if ( count == 0 ) | ||
105 | continue; | ||
25 | 106 | ||
26 | int count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | 107 | std::string nfile( count, '\0' ); |
27 | pNotify->FileNameLength / sizeof( WCHAR ), szFile, | ||
28 | MAX_PATH - 1, NULL, NULL ); | ||
29 | szFile[count] = TEXT( '\0' ); | ||
30 | 108 | ||
31 | std::string nfile( szFile ); | 109 | count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, |
110 | pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, | ||
111 | NULL, NULL ); | ||
32 | 112 | ||
33 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { | 113 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { |
34 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); | 114 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); |
@@ -41,12 +121,59 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve | |||
41 | 121 | ||
42 | pWatch->LastModifiedEvent.fileName = nfile; | 122 | pWatch->LastModifiedEvent.fileName = nfile; |
43 | pWatch->LastModifiedEvent.file = fifile; | 123 | pWatch->LastModifiedEvent.file = fifile; |
124 | } else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) { | ||
125 | pWatch->OldFiles.emplace_back( nfile, pNotify->FileId ); | ||
126 | skip = true; | ||
127 | } else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) { | ||
128 | std::string oldFile; | ||
129 | LARGE_INTEGER oldFileId{}; | ||
130 | |||
131 | for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) { | ||
132 | if ( it->second.QuadPart == pNotify->FileId.QuadPart ) { | ||
133 | oldFile = it->first; | ||
134 | oldFileId = it->second; | ||
135 | it = pWatch->OldFiles.erase( it ); | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if ( oldFile.empty() ) { | ||
141 | pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED ); | ||
142 | skip = true; | ||
143 | } else { | ||
144 | pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME ); | ||
145 | } | ||
44 | } | 146 | } |
45 | 147 | ||
46 | if ( !skip ) { | 148 | if ( !skip ) { |
47 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); | 149 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); |
48 | } | 150 | } |
49 | } while ( pNotify->NextEntryOffset != 0 ); | 151 | } while ( pNotify->NextEntryOffset != 0 ); |
152 | } | ||
153 | |||
154 | /// Unpacks events and passes them to a user defined callback. | ||
155 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { | ||
156 | if ( NULL == lpOverlapped ) { | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; | ||
161 | WatcherWin32* pWatch = tWatch->Watch; | ||
162 | |||
163 | if ( dwNumberOfBytesTransfered == 0 ) { | ||
164 | if ( nullptr != pWatch && !pWatch->StopNow ) { | ||
165 | RefreshWatch( tWatch ); | ||
166 | } else { | ||
167 | return; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // Fork watch depending on the Windows API supported | ||
172 | if ( pWatch->Extended ) { | ||
173 | WatchCallbackEx( pWatch ); | ||
174 | } else { | ||
175 | WatchCallbackOld( pWatch ); | ||
176 | } | ||
50 | 177 | ||
51 | if ( !pWatch->StopNow ) { | 178 | if ( !pWatch->StopNow ) { |
52 | RefreshWatch( tWatch ); | 179 | RefreshWatch( tWatch ); |
@@ -54,11 +181,40 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve | |||
54 | } | 181 | } |
55 | 182 | ||
56 | /// Refreshes the directory monitoring. | 183 | /// Refreshes the directory monitoring. |
57 | bool RefreshWatch( WatcherStructWin32* pWatch ) { | 184 | RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) { |
58 | return ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer, | 185 | initReadDirectoryChangesEx(); |
59 | sizeof( pWatch->Watch->Buffer ), pWatch->Watch->Recursive, | 186 | |
60 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | 187 | bool bRet = false; |
61 | NULL ) != 0; | 188 | RefreshResult ret = RefreshResult::Failed; |
189 | pWatch->Watch->Extended = false; | ||
190 | |||
191 | if ( pReadDirectoryChangesExW ) { | ||
192 | bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), | ||
193 | (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, | ||
194 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | ||
195 | NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0; | ||
196 | if ( bRet ) { | ||
197 | ret = RefreshResult::SucessEx; | ||
198 | pWatch->Watch->Extended = true; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if ( !bRet ) { | ||
203 | bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), | ||
204 | (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, | ||
205 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | ||
206 | NULL ) != 0; | ||
207 | |||
208 | if ( bRet ) | ||
209 | ret = RefreshResult::Success; | ||
210 | } | ||
211 | |||
212 | if ( !bRet ) { | ||
213 | std::string error = std::to_string( GetLastError() ); | ||
214 | Errors::Log::createLastError( Errors::WatcherFailed, error ); | ||
215 | } | ||
216 | |||
217 | return ret; | ||
62 | } | 218 | } |
63 | 219 | ||
64 | /// Stops monitoring a directory. | 220 | /// Stops monitoring a directory. |
@@ -70,19 +226,17 @@ void DestroyWatch( WatcherStructWin32* pWatch ) { | |||
70 | CloseHandle( pWatch->Watch->DirHandle ); | 226 | CloseHandle( pWatch->Watch->DirHandle ); |
71 | efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); | 227 | efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); |
72 | efSAFE_DELETE( pWatch->Watch ); | 228 | efSAFE_DELETE( pWatch->Watch ); |
229 | efSAFE_DELETE( pWatch ); | ||
73 | } | 230 | } |
74 | } | 231 | } |
75 | 232 | ||
76 | /// Starts monitoring a directory. | 233 | /// Starts monitoring a directory. |
77 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | 234 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, |
78 | HANDLE iocp ) { | 235 | DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) { |
79 | WatcherStructWin32* tWatch; | 236 | WatcherStructWin32* tWatch = new WatcherStructWin32(); |
80 | size_t ptrsize = sizeof( *tWatch ); | 237 | WatcherWin32* pWatch = new WatcherWin32(bufferSize); |
81 | tWatch = static_cast<WatcherStructWin32*>( | 238 | if (tWatch) |
82 | HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) ); | 239 | tWatch->Watch = pWatch; |
83 | |||
84 | WatcherWin32* pWatch = new WatcherWin32(); | ||
85 | tWatch->Watch = pWatch; | ||
86 | 240 | ||
87 | pWatch->DirHandle = CreateFileW( | 241 | pWatch->DirHandle = CreateFileW( |
88 | szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, | 242 | szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
@@ -90,17 +244,17 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD Noti | |||
90 | 244 | ||
91 | if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && | 245 | if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && |
92 | CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { | 246 | CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { |
93 | pWatch->NotifyFilter = NotifyFilter; | 247 | pWatch->NotifyFilter = notifyFilter; |
94 | pWatch->Recursive = recursive; | 248 | pWatch->Recursive = recursive; |
95 | 249 | ||
96 | if ( RefreshWatch( tWatch ) ) { | 250 | if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) { |
97 | return tWatch; | 251 | return tWatch; |
98 | } | 252 | } |
99 | } | 253 | } |
100 | 254 | ||
101 | CloseHandle( pWatch->DirHandle ); | 255 | CloseHandle( pWatch->DirHandle ); |
102 | efSAFE_DELETE( pWatch->Watch ); | 256 | efSAFE_DELETE( pWatch->Watch ); |
103 | HeapFree( GetProcessHeap(), 0, tWatch ); | 257 | efSAFE_DELETE( tWatch ); |
104 | return NULL; | 258 | return NULL; |
105 | } | 259 | } |
106 | 260 | ||
diff --git a/src/3rdParty/efsw/WatcherWin32.hpp b/src/3rdParty/efsw/WatcherWin32.hpp index 71e13be..ea1e8e4 100755..100644 --- a/src/3rdParty/efsw/WatcherWin32.hpp +++ b/src/3rdParty/efsw/WatcherWin32.hpp | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <efsw/FileInfo.hpp> | 4 | #include <efsw/FileInfo.hpp> |
5 | #include <efsw/FileWatcherImpl.hpp> | 5 | #include <efsw/FileWatcherImpl.hpp> |
6 | #include <vector> | ||
6 | 7 | ||
7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
8 | 9 | ||
@@ -21,6 +22,8 @@ namespace efsw { | |||
21 | 22 | ||
22 | class WatcherWin32; | 23 | class WatcherWin32; |
23 | 24 | ||
25 | enum RefreshResult { Failed, Success, SucessEx }; | ||
26 | |||
24 | /// Internal watch data | 27 | /// Internal watch data |
25 | struct WatcherStructWin32 { | 28 | struct WatcherStructWin32 { |
26 | OVERLAPPED Overlapped; | 29 | OVERLAPPED Overlapped; |
@@ -32,39 +35,41 @@ struct sLastModifiedEvent { | |||
32 | std::string fileName; | 35 | std::string fileName; |
33 | }; | 36 | }; |
34 | 37 | ||
35 | bool RefreshWatch( WatcherStructWin32* pWatch ); | 38 | RefreshResult RefreshWatch( WatcherStructWin32* pWatch ); |
36 | 39 | ||
37 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); | 40 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); |
38 | 41 | ||
39 | void DestroyWatch( WatcherStructWin32* pWatch ); | 42 | void DestroyWatch( WatcherStructWin32* pWatch ); |
40 | 43 | ||
41 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | 44 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, |
42 | HANDLE iocp ); | 45 | DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ); |
43 | 46 | ||
44 | class WatcherWin32 : public Watcher { | 47 | class WatcherWin32 : public Watcher { |
45 | public: | 48 | public: |
46 | WatcherWin32() : | 49 | WatcherWin32(DWORD dwBufferSize) : |
47 | Struct( NULL ), | 50 | Struct( NULL ), |
48 | DirHandle( NULL ), | 51 | DirHandle( NULL ), |
52 | Buffer(), | ||
49 | lParam( 0 ), | 53 | lParam( 0 ), |
50 | NotifyFilter( 0 ), | 54 | NotifyFilter( 0 ), |
51 | StopNow( false ), | 55 | StopNow( false ), |
56 | Extended( false ), | ||
52 | Watch( NULL ), | 57 | Watch( NULL ), |
53 | DirName( NULL ) {} | 58 | DirName( NULL ) { |
59 | Buffer.resize(dwBufferSize); | ||
60 | } | ||
54 | 61 | ||
55 | WatcherStructWin32* Struct; | 62 | WatcherStructWin32* Struct; |
56 | HANDLE DirHandle; | 63 | HANDLE DirHandle; |
57 | BYTE Buffer | 64 | std::vector<BYTE> Buffer; |
58 | [63 * | ||
59 | 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched | ||
60 | // is on the network! (see | ||
61 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) | ||
62 | LPARAM lParam; | 65 | LPARAM lParam; |
63 | DWORD NotifyFilter; | 66 | DWORD NotifyFilter; |
64 | bool StopNow; | 67 | bool StopNow; |
68 | bool Extended; | ||
65 | FileWatcherImpl* Watch; | 69 | FileWatcherImpl* Watch; |
66 | char* DirName; | 70 | char* DirName; |
67 | sLastModifiedEvent LastModifiedEvent; | 71 | sLastModifiedEvent LastModifiedEvent; |
72 | std::vector<std::pair<std::string, LARGE_INTEGER>> OldFiles; | ||
68 | }; | 73 | }; |
69 | 74 | ||
70 | } // namespace efsw | 75 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/base.hpp b/src/3rdParty/efsw/base.hpp index 43abc4f..43abc4f 100755..100644 --- a/src/3rdParty/efsw/base.hpp +++ b/src/3rdParty/efsw/base.hpp | |||
diff --git a/src/3rdParty/efsw/efsw.h b/src/3rdParty/efsw/efsw.h index 28e63e2..30cf595 100755..100644 --- a/src/3rdParty/efsw/efsw.h +++ b/src/3rdParty/efsw/efsw.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | @author Sepul Sepehr Taghdisian | 2 | @author Sepul Sepehr Taghdisian |
3 | 3 | ||
4 | Copyright (c) 2013 Martin Lucas Golini | 4 | Copyright (c) 2024 MartÃn Lucas Golini |
5 | 5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | of this software and associated documentation files (the "Software"), to deal | 7 | of this software and associated documentation files (the "Software"), to deal |
@@ -32,31 +32,31 @@ | |||
32 | extern "C" { | 32 | extern "C" { |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | #if defined(_WIN32) | 35 | #if defined( _WIN32 ) |
36 | #ifdef EFSW_DYNAMIC | 36 | #ifdef EFSW_DYNAMIC |
37 | // Windows platforms | 37 | // Windows platforms |
38 | #ifdef EFSW_EXPORTS | 38 | #ifdef EFSW_EXPORTS |
39 | // From DLL side, we must export | 39 | // From DLL side, we must export |
40 | #define EFSW_API __declspec(dllexport) | 40 | #define EFSW_API __declspec( dllexport ) |
41 | #else | ||
42 | // From client application side, we must import | ||
43 | #define EFSW_API __declspec(dllimport) | ||
44 | #endif | ||
45 | #else | ||
46 | // No specific directive needed for static build | ||
47 | #ifndef EFSW_API | ||
48 | #define EFSW_API | ||
49 | #endif | ||
50 | #endif | ||
51 | #else | 41 | #else |
52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | 42 | // From client application side, we must import |
53 | #define EFSW_API __attribute__ ((visibility("default"))) | 43 | #define EFSW_API __declspec( dllimport ) |
54 | #endif | 44 | #endif |
55 | 45 | #else | |
56 | // Other platforms don't need to define anything | 46 | // No specific directive needed for static build |
57 | #ifndef EFSW_API | 47 | #ifndef EFSW_API |
58 | #define EFSW_API | 48 | #define EFSW_API |
59 | #endif | 49 | #endif |
50 | #endif | ||
51 | #else | ||
52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | ||
53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) | ||
54 | #endif | ||
55 | |||
56 | // Other platforms don't need to define anything | ||
57 | #ifndef EFSW_API | ||
58 | #define EFSW_API | ||
59 | #endif | ||
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | /// Type for a watch id | 62 | /// Type for a watch id |
@@ -65,84 +65,127 @@ typedef long efsw_watchid; | |||
65 | /// Type for watcher | 65 | /// Type for watcher |
66 | typedef void* efsw_watcher; | 66 | typedef void* efsw_watcher; |
67 | 67 | ||
68 | enum efsw_action | 68 | enum efsw_action { |
69 | { | 69 | EFSW_ADD = 1, /// Sent when a file is created or renamed |
70 | EFSW_ADD = 1, /// Sent when a file is created or renamed | 70 | EFSW_DELETE = 2, /// Sent when a file is deleted or renamed |
71 | EFSW_DELETE = 2, /// Sent when a file is deleted or renamed | 71 | EFSW_MODIFIED = 3, /// Sent when a file is modified |
72 | EFSW_MODIFIED = 3, /// Sent when a file is modified | 72 | EFSW_MOVED = 4 /// Sent when a file is moved |
73 | EFSW_MOVED = 4 /// Sent when a file is moved | 73 | }; |
74 | |||
75 | enum efsw_error { | ||
76 | EFSW_NOTFOUND = -1, | ||
77 | EFSW_REPEATED = -2, | ||
78 | EFSW_OUTOFSCOPE = -3, | ||
79 | EFSW_NOTREADABLE = -4, | ||
80 | EFSW_REMOTE = -5, | ||
81 | EFSW_WATCHER_FAILED = -6, | ||
82 | EFSW_UNSPECIFIED = -7 | ||
74 | }; | 83 | }; |
75 | 84 | ||
76 | enum efsw_error | 85 | enum efsw_option { |
77 | { | 86 | /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and |
78 | EFSW_NOTFOUND = -1, | 87 | /// file system events may be dropped. For that, using a different (bigger) buffer size |
79 | EFSW_REPEATED = -2, | 88 | /// can be defined here, but note that this does not work for network drives, |
80 | EFSW_OUTOFSCOPE = -3, | 89 | /// because a buffer larger than 64K will fail the folder being watched, see |
81 | EFSW_NOTREADABLE = -4, | 90 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) |
82 | EFSW_REMOTE = -5, | 91 | EFSW_OPT_WIN_BUFFER_SIZE = 1, |
83 | EFSW_UNSPECIFIED = -6 | 92 | /// For Windows, per default all events are captured but we might only be interested |
93 | /// in a subset; the value of the option should be set to a bitwise or'ed set of | ||
94 | /// FILE_NOTIFY_CHANGE_* flags. | ||
95 | EFSW_OPT_WIN_NOTIFY_FILTER = 2, | ||
96 | /// For macOS (FSEvents backend), per default all modified event types are capture but we might | ||
97 | // only be interested in a subset; the value of the option should be set to a set of bitwise | ||
98 | // from: | ||
99 | // kFSEventStreamEventFlagItemFinderInfoMod | ||
100 | // kFSEventStreamEventFlagItemModified | ||
101 | // kFSEventStreamEventFlagItemInodeMetaMod | ||
102 | // Default configuration will set the 3 flags | ||
103 | EFSW_OPT_MAC_MODIFIED_FILTER = 3, | ||
104 | /// macOS sometimes informs incorrect or old file states that may confuse the consumer | ||
105 | /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing | ||
106 | /// the number of events reported. This will have an small performance and memory impact as a | ||
107 | /// consequence. | ||
108 | EFSW_OPT_MAC_SANITIZE_EVENTS = 4, | ||
109 | /// Linux does not support natively recursive watchers. This means that when using recursive | ||
110 | /// watches efsw registers new watchers for each directory. If new file are created between | ||
111 | /// the time efsw takes to register the new directory those events might be missed. To avoid | ||
112 | /// missing new file notifications efsw will trigger synthetic new file events for existing | ||
113 | /// files in the new directroy watched. This might have the unintended consequence of sending | ||
114 | /// duplicated created events due to the system also emitting this event. | ||
115 | LINUX_PRODUCE_SYNTHETIC_EVENTS = 5, | ||
84 | }; | 116 | }; |
85 | 117 | ||
86 | /// Basic interface for listening for file events. | 118 | /// Basic interface for listening for file events. |
87 | typedef void (*efsw_pfn_fileaction_callback) ( | 119 | typedef void ( *efsw_pfn_fileaction_callback )( efsw_watcher watcher, efsw_watchid watchid, |
88 | efsw_watcher watcher, | 120 | const char* dir, const char* filename, |
89 | efsw_watchid watchid, | 121 | enum efsw_action action, const char* old_filename, |
90 | const char* dir, | 122 | void* param ); |
91 | const char* filename, | 123 | |
92 | enum efsw_action action, | 124 | typedef struct { |
93 | const char* old_filename, | 125 | enum efsw_option option; |
94 | void* param | 126 | int value; |
95 | ); | 127 | } efsw_watcher_option; |
96 | 128 | ||
97 | /** | 129 | /** |
98 | * Creates a new file-watcher | 130 | * Creates a new file-watcher |
99 | * @param generic_mode Force the use of the Generic file watcher | 131 | * @param generic_mode Force the use of the Generic file watcher |
100 | */ | 132 | */ |
101 | efsw_watcher EFSW_API efsw_create(int generic_mode); | 133 | efsw_watcher EFSW_API efsw_create( int generic_mode ); |
102 | 134 | ||
103 | /// Release the file-watcher and unwatch any directories | 135 | /// Release the file-watcher and unwatch any directories |
104 | void EFSW_API efsw_release(efsw_watcher watcher); | 136 | void EFSW_API efsw_release( efsw_watcher watcher ); |
105 | 137 | ||
106 | /// Retreive last error occured by file-watcher | 138 | /// Retrieve last error occured by file-watcher |
107 | EFSW_API const char* efsw_getlasterror(); | 139 | EFSW_API const char* efsw_getlasterror(); |
108 | 140 | ||
109 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | 141 | /// Reset file-watcher last error |
110 | /// For backwards compatibility. | 142 | EFSW_API void efsw_clearlasterror(); |
143 | |||
144 | /// Add a directory watch | ||
111 | /// On error returns WatchID with Error type. | 145 | /// On error returns WatchID with Error type. |
112 | efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, | 146 | efsw_watchid EFSW_API efsw_addwatch( efsw_watcher watcher, const char* directory, |
113 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); | 147 | efsw_pfn_fileaction_callback callback_fn, int recursive, |
148 | void* param ); | ||
149 | |||
150 | /// Add a directory watch, specifying options | ||
151 | /// @param options Pointer to an array of watcher options | ||
152 | /// @param nr_options Number of options referenced by \p options | ||
153 | efsw_watchid EFSW_API efsw_addwatch_withoptions( efsw_watcher watcher, const char* directory, | ||
154 | efsw_pfn_fileaction_callback callback_fn, | ||
155 | int recursive, efsw_watcher_option* options, | ||
156 | int options_number, void* param ); | ||
114 | 157 | ||
115 | /// Remove a directory watch. This is a brute force search O(nlogn). | 158 | /// Remove a directory watch. This is a brute force search O(nlogn). |
116 | void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); | 159 | void EFSW_API efsw_removewatch( efsw_watcher watcher, const char* directory ); |
117 | 160 | ||
118 | /// Remove a directory watch. This is a map lookup O(logn). | 161 | /// Remove a directory watch. This is a map lookup O(logn). |
119 | void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); | 162 | void EFSW_API efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ); |
120 | 163 | ||
121 | /// Starts watching ( in other thread ) | 164 | /// Starts watching ( in other thread ) |
122 | void EFSW_API efsw_watch(efsw_watcher watcher); | 165 | void EFSW_API efsw_watch( efsw_watcher watcher ); |
123 | 166 | ||
124 | /** | 167 | /** |
125 | * Allow recursive watchers to follow symbolic links to other directories | 168 | * Allow recursive watchers to follow symbolic links to other directories |
126 | * followSymlinks is disabled by default | 169 | * followSymlinks is disabled by default |
127 | */ | 170 | */ |
128 | void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); | 171 | void EFSW_API efsw_follow_symlinks( efsw_watcher watcher, int enable ); |
129 | 172 | ||
130 | /** @return If can follow symbolic links to directorioes */ | 173 | /** @return If can follow symbolic links to directorioes */ |
131 | int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); | 174 | int EFSW_API efsw_follow_symlinks_isenabled( efsw_watcher watcher ); |
132 | 175 | ||
133 | /** | 176 | /** |
134 | * When enable this it will allow symlinks to watch recursively out of the pointed directory. | 177 | * When enable this it will allow symlinks to watch recursively out of the pointed directory. |
135 | * follorSymlinks must be enabled to this work. | 178 | * follorSymlinks must be enabled to this work. |
136 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, | 179 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not |
137 | * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. | 180 | * allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid great |
138 | * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). | 181 | * levels of recursion. Enabling this could lead in infinite recursion, and crash the watcher ( it |
139 | * Buy enabling out of scope links, it will allow this behavior. | 182 | * will try not to avoid this ). Buy enabling out of scope links, it will allow this behavior. |
140 | * allowOutOfScopeLinks are disabled by default. | 183 | * allowOutOfScopeLinks are disabled by default. |
141 | */ | 184 | */ |
142 | void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); | 185 | void EFSW_API efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ); |
143 | 186 | ||
144 | /// @return Returns if out of scope links are allowed | 187 | /// @return Returns if out of scope links are allowed |
145 | int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); | 188 | int EFSW_API efsw_outofscopelinks_isallowed( efsw_watcher watcher ); |
146 | 189 | ||
147 | #ifdef __cplusplus | 190 | #ifdef __cplusplus |
148 | } | 191 | } |
diff --git a/src/3rdParty/efsw/efsw.hpp b/src/3rdParty/efsw/efsw.hpp index 12af116..11a5dec 100755..100644 --- a/src/3rdParty/efsw/efsw.hpp +++ b/src/3rdParty/efsw/efsw.hpp | |||
@@ -1,195 +1,261 @@ | |||
1 | /** | 1 | /** |
2 | @author MartÃn Lucas Golini | 2 | @author MartÃn Lucas Golini |
3 | 3 | ||
4 | Copyright (c) 2013 MartÃn Lucas Golini | 4 | Copyright (c) 2024 MartÃn Lucas Golini |
5 | 5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | of this software and associated documentation files (the "Software"), to deal | 7 | of this software and associated documentation files (the "Software"), to deal |
8 | in the Software without restriction, including without limitation the rights | 8 | in the Software without restriction, including without limitation the rights |
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | copies of the Software, and to permit persons to whom the Software is | 10 | copies of the Software, and to permit persons to whom the Software is |
11 | furnished to do so, subject to the following conditions: | 11 | furnished to do so, subject to the following conditions: |
12 | 12 | ||
13 | The above copyright notice and this permission notice shall be included in | 13 | The above copyright notice and this permission notice shall be included in |
14 | all copies or substantial portions of the Software. | 14 | all copies or substantial portions of the Software. |
15 | 15 | ||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | THE SOFTWARE. | 22 | THE SOFTWARE. |
23 | 23 | ||
24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) | 24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) |
25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. | 25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #ifndef ESFW_HPP | 28 | #ifndef ESFW_HPP |
29 | #define ESFW_HPP | 29 | #define ESFW_HPP |
30 | 30 | ||
31 | #include <list> | 31 | #include <string> |
32 | #include <string> | 32 | #include <vector> |
33 | 33 | ||
34 | #if defined( _WIN32 ) | 34 | #if defined( _WIN32 ) |
35 | #ifdef EFSW_DYNAMIC | 35 | #ifdef EFSW_DYNAMIC |
36 | // Windows platforms | 36 | // Windows platforms |
37 | #ifdef EFSW_EXPORTS | 37 | #ifdef EFSW_EXPORTS |
38 | // From DLL side, we must export | 38 | // From DLL side, we must export |
39 | #define EFSW_API __declspec( dllexport ) | 39 | #define EFSW_API __declspec( dllexport ) |
40 | #else | 40 | #else |
41 | // From client application side, we must import | 41 | // From client application side, we must import |
42 | #define EFSW_API __declspec( dllimport ) | 42 | #define EFSW_API __declspec( dllimport ) |
43 | #endif | 43 | #endif |
44 | #else | 44 | #else |
45 | // No specific directive needed for static build | 45 | // No specific directive needed for static build |
46 | #ifndef EFSW_API | 46 | #ifndef EFSW_API |
47 | #define EFSW_API | 47 | #define EFSW_API |
48 | #endif | 48 | #endif |
49 | #endif | 49 | #endif |
50 | #else | 50 | #else |
51 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | 51 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) |
52 | #ifndef EFSW_API | 52 | #ifndef EFSW_API |
53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) | 53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) |
54 | #endif | 54 | #endif |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | // Other platforms don't need to define anything | 57 | // Other platforms don't need to define anything |
58 | #ifndef EFSW_API | 58 | #ifndef EFSW_API |
59 | #define EFSW_API | 59 | #define EFSW_API |
60 | #endif | 60 | #endif |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | namespace efsw { | 63 | namespace efsw { |
64 | 64 | ||
65 | /// Type for a watch id | 65 | /// Type for a watch id |
66 | typedef long WatchID; | 66 | typedef long WatchID; |
67 | 67 | ||
68 | // forward declarations | 68 | // forward declarations |
69 | class FileWatcherImpl; | 69 | class FileWatcherImpl; |
70 | class FileWatchListener; | 70 | class FileWatchListener; |
71 | 71 | class WatcherOption; | |
72 | /// Actions to listen for. Rename will send two events, one for | 72 | |
73 | /// the deletion of the old file, and one for the creation of the | 73 | /// Actions to listen for. Rename will send two events, one for |
74 | /// new file. | 74 | /// the deletion of the old file, and one for the creation of the |
75 | namespace Actions { | 75 | /// new file. |
76 | enum Action { | 76 | namespace Actions { |
77 | /// Sent when a file is created or renamed | 77 | enum Action { |
78 | Add = 1, | 78 | /// Sent when a file is created or renamed |
79 | /// Sent when a file is deleted or renamed | 79 | Add = 1, |
80 | Delete = 2, | 80 | /// Sent when a file is deleted or renamed |
81 | /// Sent when a file is modified | 81 | Delete = 2, |
82 | Modified = 3, | 82 | /// Sent when a file is modified |
83 | /// Sent when a file is moved | 83 | Modified = 3, |
84 | Moved = 4 | 84 | /// Sent when a file is moved |
85 | }; | 85 | Moved = 4 |
86 | } | 86 | }; |
87 | typedef Actions::Action Action; | 87 | } |
88 | 88 | typedef Actions::Action Action; | |
89 | /// Errors log namespace | 89 | |
90 | namespace Errors { | 90 | /// Errors log namespace |
91 | 91 | namespace Errors { | |
92 | enum Error { | 92 | |
93 | FileNotFound = -1, | 93 | enum Error { |
94 | FileRepeated = -2, | 94 | NoError = 0, |
95 | FileOutOfScope = -3, | 95 | FileNotFound = -1, |
96 | FileNotReadable = -4, | 96 | FileRepeated = -2, |
97 | FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to | 97 | FileOutOfScope = -3, |
98 | watch this directory ). */ | 98 | FileNotReadable = -4, |
99 | Unspecified = -6 | 99 | /// Directory in remote file system |
100 | }; | 100 | /// ( create a generic FileWatcher instance to watch this directory ). |
101 | 101 | FileRemote = -5, | |
102 | class EFSW_API Log { | 102 | /// File system watcher failed to watch for changes. |
103 | public: | 103 | WatcherFailed = -6, |
104 | /// @return The last error logged | 104 | Unspecified = -7 |
105 | static std::string getLastErrorLog(); | 105 | }; |
106 | 106 | ||
107 | /// Creates an error of the type specified | 107 | class EFSW_API Log { |
108 | static Error createLastError( Error err, std::string log ); | 108 | public: |
109 | }; | 109 | /// @return The last error logged |
110 | 110 | static std::string getLastErrorLog(); | |
111 | } // namespace Errors | 111 | |
112 | typedef Errors::Error Error; | 112 | /// @return The code of the last error logged |
113 | 113 | static Error getLastErrorCode(); | |
114 | /// Listens to files and directories and dispatches events | 114 | |
115 | /// to notify the listener of files and directories changes. | 115 | /// Reset last error |
116 | /// @class FileWatcher | 116 | static void clearLastError(); |
117 | class EFSW_API FileWatcher { | 117 | |
118 | public: | 118 | /// Creates an error of the type specified |
119 | /// Default constructor, will use the default platform file watcher | 119 | static Error createLastError( Error err, std::string log ); |
120 | FileWatcher(); | 120 | }; |
121 | 121 | ||
122 | /// Constructor that lets you force the use of the Generic File Watcher | 122 | } // namespace Errors |
123 | explicit FileWatcher( bool useGenericFileWatcher ); | 123 | typedef Errors::Error Error; |
124 | 124 | ||
125 | virtual ~FileWatcher(); | 125 | /// Optional file watcher settings. |
126 | 126 | namespace Options { | |
127 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | 127 | enum Option { |
128 | /// For backwards compatibility. | 128 | /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and |
129 | /// On error returns WatchID with Error type. | 129 | /// file system events may be dropped. For that, using a different (bigger) buffer size |
130 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); | 130 | /// can be defined here, but note that this does not work for network drives, |
131 | 131 | /// because a buffer larger than 64K will fail the folder being watched, see | |
132 | /// Add a directory watch | 132 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) |
133 | /// On error returns WatchID with Error type. | 133 | WinBufferSize = 1, |
134 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 134 | /// For Windows, per default all events are captured but we might only be interested |
135 | 135 | /// in a subset; the value of the option should be set to a bitwise or'ed set of | |
136 | /// Remove a directory watch. This is a brute force search O(nlogn). | 136 | /// FILE_NOTIFY_CHANGE_* flags. |
137 | void removeWatch( const std::string& directory ); | 137 | WinNotifyFilter = 2, |
138 | 138 | /// For macOS (FSEvents backend), per default all modified event types are capture but we might | |
139 | /// Remove a directory watch. This is a map lookup O(logn). | 139 | /// only be interested in a subset; the value of the option should be set to a set of bitwise |
140 | void removeWatch( WatchID watchid ); | 140 | /// from: |
141 | 141 | /// kFSEventStreamEventFlagItemFinderInfoMod | |
142 | /// Starts watching ( in other thread ) | 142 | /// kFSEventStreamEventFlagItemModified |
143 | void watch(); | 143 | /// kFSEventStreamEventFlagItemInodeMetaMod |
144 | 144 | /// Default configuration will set the 3 flags | |
145 | /// @return Returns a list of the directories that are being watched | 145 | MacModifiedFilter = 3, |
146 | std::list<std::string> directories(); | 146 | /// macOS sometimes informs incorrect or old file states that may confuse the consumer |
147 | 147 | /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing | |
148 | /** Allow recursive watchers to follow symbolic links to other directories | 148 | /// the number of events reported. This will have an small performance and memory impact as a |
149 | * followSymlinks is disabled by default | 149 | /// consequence. |
150 | */ | 150 | MacSanitizeEvents = 4, |
151 | void followSymlinks( bool follow ); | 151 | /// Linux does not support natively recursive watchers. This means that when using recursive |
152 | 152 | /// watches efsw registers new watchers for each directory. If new file are created between | |
153 | /** @return If can follow symbolic links to directorioes */ | 153 | /// the time efsw takes to register the new directory those events might be missed. To avoid |
154 | const bool& followSymlinks() const; | 154 | /// missing new file notifications efsw will trigger synthetic created file events for existing |
155 | 155 | /// files in the new directroy watched. This might have the unintended consequence of sending | |
156 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. | 156 | /// duplicated created events due to the system also emitting this event. |
157 | * follorSymlinks must be enabled to this work. | 157 | LinuxProduceSyntheticEvents = 5, |
158 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is | 158 | }; |
159 | * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid | 159 | } |
160 | * great levels of recursion. Enabling this could lead in infinite recursion, and crash the | 160 | typedef Options::Option Option; |
161 | * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow | 161 | |
162 | * this behavior. allowOutOfScopeLinks are disabled by default. | 162 | /// Listens to files and directories and dispatches events |
163 | */ | 163 | /// to notify the listener of files and directories changes. |
164 | void allowOutOfScopeLinks( bool allow ); | 164 | /// @class FileWatcher |
165 | 165 | class EFSW_API FileWatcher { | |
166 | /// @return Returns if out of scope links are allowed | 166 | public: |
167 | const bool& allowOutOfScopeLinks() const; | 167 | /// Default constructor, will use the default platform file watcher |
168 | 168 | FileWatcher(); | |
169 | private: | 169 | |
170 | /// The implementation | 170 | /// Constructor that lets you force the use of the Generic File Watcher |
171 | FileWatcherImpl* mImpl; | 171 | explicit FileWatcher( bool useGenericFileWatcher ); |
172 | bool mFollowSymlinks; | 172 | |
173 | bool mOutOfScopeLinks; | 173 | virtual ~FileWatcher(); |
174 | }; | 174 | |
175 | 175 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | |
176 | /// Basic interface for listening for file events. | 176 | /// For backwards compatibility. |
177 | /// @class FileWatchListener | 177 | /// On error returns WatchID with Error type. |
178 | class FileWatchListener { | 178 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); |
179 | public: | 179 | |
180 | virtual ~FileWatchListener() {} | 180 | /// Add a directory watch |
181 | 181 | /// On error returns WatchID with Error type. | |
182 | /// Handles the action file action | 182 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); |
183 | /// @param watchid The watch id for the directory | 183 | |
184 | /// @param dir The directory | 184 | /// Add a directory watch, allowing customization with options |
185 | /// @param filename The filename that was accessed (not full path) | 185 | /// @param directory The folder to be watched |
186 | /// @param action Action that was performed | 186 | /// @param watcher The listener to receive events |
187 | /// @param oldFilename The name of the file or directory moved | 187 | /// @param recursive Set this to true to include subdirectories |
188 | virtual void handleFileAction( WatchID watchid, const std::string& dir, | 188 | /// @param options Allows customization of a watcher |
189 | const std::string& filename, Action action, | 189 | /// @return Returns the watch id for the directory or, on error, a WatchID with Error type. |
190 | std::string oldFilename = "" ) = 0; | 190 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
191 | }; | 191 | const std::vector<WatcherOption>& options ); |
192 | 192 | ||
193 | } // namespace efsw | 193 | /// Remove a directory watch. This is a brute force search O(nlogn). |
194 | 194 | void removeWatch( const std::string& directory ); | |
195 | #endif | 195 | |
196 | /// Remove a directory watch. This is a map lookup O(logn). | ||
197 | void removeWatch( WatchID watchid ); | ||
198 | |||
199 | /// Starts watching ( in other thread ) | ||
200 | void watch(); | ||
201 | |||
202 | /// @return Returns a list of the directories that are being watched | ||
203 | std::vector<std::string> directories(); | ||
204 | |||
205 | /** Allow recursive watchers to follow symbolic links to other directories | ||
206 | * followSymlinks is disabled by default | ||
207 | */ | ||
208 | void followSymlinks( bool follow ); | ||
209 | |||
210 | /** @return If can follow symbolic links to directorioes */ | ||
211 | const bool& followSymlinks() const; | ||
212 | |||
213 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. | ||
214 | * follorSymlinks must be enabled to this work. | ||
215 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is | ||
216 | * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid | ||
217 | * great levels of recursion. Enabling this could lead in infinite recursion, and crash the | ||
218 | * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow | ||
219 | * this behavior. allowOutOfScopeLinks are disabled by default. | ||
220 | */ | ||
221 | void allowOutOfScopeLinks( bool allow ); | ||
222 | |||
223 | /// @return Returns if out of scope links are allowed | ||
224 | const bool& allowOutOfScopeLinks() const; | ||
225 | |||
226 | private: | ||
227 | /// The implementation | ||
228 | FileWatcherImpl* mImpl; | ||
229 | bool mFollowSymlinks; | ||
230 | bool mOutOfScopeLinks; | ||
231 | }; | ||
232 | |||
233 | /// Basic interface for listening for file events. | ||
234 | /// @class FileWatchListener | ||
235 | class FileWatchListener { | ||
236 | public: | ||
237 | virtual ~FileWatchListener() {} | ||
238 | |||
239 | /// Handles the action file action | ||
240 | /// @param watchid The watch id for the directory | ||
241 | /// @param dir The directory | ||
242 | /// @param filename The filename that was accessed (not full path) | ||
243 | /// @param action Action that was performed | ||
244 | /// @param oldFilename The name of the file or directory moved | ||
245 | virtual void handleFileAction( WatchID watchid, const std::string& dir, | ||
246 | const std::string& filename, Action action, | ||
247 | std::string oldFilename = "" ) = 0; | ||
248 | }; | ||
249 | |||
250 | /// Optional, typically platform specific parameter for customization of a watcher. | ||
251 | /// @class WatcherOption | ||
252 | class WatcherOption { | ||
253 | public: | ||
254 | WatcherOption( Option option, int value ) : mOption( option ), mValue( value ){}; | ||
255 | Option mOption; | ||
256 | int mValue; | ||
257 | }; | ||
258 | |||
259 | } // namespace efsw | ||
260 | |||
261 | #endif | ||
diff --git a/src/3rdParty/efsw/inotify-nosys.h b/src/3rdParty/efsw/inotify-nosys.h index be1e627..be1e627 100755..100644 --- a/src/3rdParty/efsw/inotify-nosys.h +++ b/src/3rdParty/efsw/inotify-nosys.h | |||
diff --git a/src/3rdParty/efsw/platform/platformimpl.hpp b/src/3rdParty/efsw/platform/platformimpl.hpp index 5442580..5442580 100755..100644 --- a/src/3rdParty/efsw/platform/platformimpl.hpp +++ b/src/3rdParty/efsw/platform/platformimpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp index 92eeb47..92eeb47 100755..100644 --- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp index 0bfba76..0bfba76 100755..100644 --- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp index 2233798..2233798 100755..100644 --- a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp index a33d827..a33d827 100755..100644 --- a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp index 37d4120..37d4120 100755..100644 --- a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp index 9322b06..9322b06 100755..100644 --- a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp index e0ae84f..772fbc9 100755..100644 --- a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp | |||
@@ -5,11 +5,10 @@ | |||
5 | 5 | ||
6 | #include <cassert> | 6 | #include <cassert> |
7 | #include <efsw/Debug.hpp> | 7 | #include <efsw/Debug.hpp> |
8 | #include <iostream> | ||
9 | 8 | ||
10 | namespace efsw { namespace Platform { | 9 | namespace efsw { namespace Platform { |
11 | 10 | ||
12 | ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { | 11 | ThreadImpl::ThreadImpl( efsw::Thread* owner ) : mIsActive( false ) { |
13 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; | 12 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; |
14 | 13 | ||
15 | if ( !mIsActive ) { | 14 | if ( !mIsActive ) { |
@@ -17,14 +16,16 @@ ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { | |||
17 | } | 16 | } |
18 | } | 17 | } |
19 | 18 | ||
19 | ThreadImpl::~ThreadImpl() { | ||
20 | terminate(); | ||
21 | } | ||
22 | |||
20 | void ThreadImpl::wait() { | 23 | void ThreadImpl::wait() { |
21 | // Wait for the thread to finish, no timeout | 24 | // Wait for the thread to finish, no timeout |
22 | if ( mIsActive ) { | 25 | if ( mIsActive ) { |
23 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); | 26 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); |
24 | 27 | ||
25 | pthread_join( mThread, NULL ); | 28 | mIsActive = pthread_join( mThread, NULL ) != 0; |
26 | |||
27 | mIsActive = false; // Reset the thread state | ||
28 | } | 29 | } |
29 | } | 30 | } |
30 | 31 | ||
@@ -41,14 +42,14 @@ void ThreadImpl::terminate() { | |||
41 | } | 42 | } |
42 | 43 | ||
43 | void* ThreadImpl::entryPoint( void* userData ) { | 44 | void* ThreadImpl::entryPoint( void* userData ) { |
44 | // The Thread instance is stored in the user data | ||
45 | Thread* owner = static_cast<Thread*>( userData ); | ||
46 | |||
47 | // Tell the thread to handle cancel requests immediatly | 45 | // Tell the thread to handle cancel requests immediatly |
48 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS | 46 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS |
49 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); | 47 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); |
50 | #endif | 48 | #endif |
51 | 49 | ||
50 | // The Thread instance is stored in the user data | ||
51 | Thread* owner = static_cast<Thread*>( userData ); | ||
52 | |||
52 | // Forward to the owner | 53 | // Forward to the owner |
53 | owner->run(); | 54 | owner->run(); |
54 | 55 | ||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp index ffc6da0..2e02f9a 100755..100644 --- a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #if defined( EFSW_PLATFORM_POSIX ) | 6 | #if defined( EFSW_PLATFORM_POSIX ) |
7 | 7 | ||
8 | #include <efsw/Atomic.hpp> | ||
8 | #include <pthread.h> | 9 | #include <pthread.h> |
9 | 10 | ||
10 | namespace efsw { | 11 | namespace efsw { |
@@ -15,7 +16,9 @@ namespace Platform { | |||
15 | 16 | ||
16 | class ThreadImpl { | 17 | class ThreadImpl { |
17 | public: | 18 | public: |
18 | ThreadImpl( Thread* owner ); | 19 | explicit ThreadImpl( efsw::Thread* owner ); |
20 | |||
21 | ~ThreadImpl(); | ||
19 | 22 | ||
20 | void wait(); | 23 | void wait(); |
21 | 24 | ||
@@ -25,7 +28,7 @@ class ThreadImpl { | |||
25 | static void* entryPoint( void* userData ); | 28 | static void* entryPoint( void* userData ); |
26 | 29 | ||
27 | pthread_t mThread; | 30 | pthread_t mThread; |
28 | bool mIsActive; | 31 | Atomic<bool> mIsActive; |
29 | }; | 32 | }; |
30 | 33 | ||
31 | } // namespace Platform | 34 | } // namespace Platform |
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp index 2b87513..2b87513 100755..100644 --- a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp index e952efc..e952efc 100755..100644 --- a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.cpp b/src/3rdParty/efsw/platform/win/MutexImpl.cpp index 62b7f83..62b7f83 100755..100644 --- a/src/3rdParty/efsw/platform/win/MutexImpl.cpp +++ b/src/3rdParty/efsw/platform/win/MutexImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.hpp b/src/3rdParty/efsw/platform/win/MutexImpl.hpp index 7b06492..7b06492 100755..100644 --- a/src/3rdParty/efsw/platform/win/MutexImpl.hpp +++ b/src/3rdParty/efsw/platform/win/MutexImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.cpp b/src/3rdParty/efsw/platform/win/SystemImpl.cpp index d1f2b21..d1f2b21 100755..100644 --- a/src/3rdParty/efsw/platform/win/SystemImpl.cpp +++ b/src/3rdParty/efsw/platform/win/SystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.hpp b/src/3rdParty/efsw/platform/win/SystemImpl.hpp index 99b4867..99b4867 100755..100644 --- a/src/3rdParty/efsw/platform/win/SystemImpl.hpp +++ b/src/3rdParty/efsw/platform/win/SystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp index d0fde8b..463934c 100755..100644 --- a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | namespace efsw { namespace Platform { | 9 | namespace efsw { namespace Platform { |
10 | 10 | ||
11 | ThreadImpl::ThreadImpl( Thread* owner ) { | 11 | ThreadImpl::ThreadImpl( efsw::Thread* owner ) { |
12 | mThread = reinterpret_cast<HANDLE>( | 12 | mThread = reinterpret_cast<HANDLE>( |
13 | _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); | 13 | _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); |
14 | 14 | ||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp index 1afb593..455f24c 100755..100644 --- a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp | |||
@@ -19,7 +19,7 @@ namespace Platform { | |||
19 | 19 | ||
20 | class ThreadImpl { | 20 | class ThreadImpl { |
21 | public: | 21 | public: |
22 | ThreadImpl( Thread* owner ); | 22 | explicit ThreadImpl( efsw::Thread* owner ); |
23 | 23 | ||
24 | ~ThreadImpl(); | 24 | ~ThreadImpl(); |
25 | 25 | ||
diff --git a/src/3rdParty/efsw/sophist.h b/src/3rdParty/efsw/sophist.h index 3a64504..82e5c36 100755..100644 --- a/src/3rdParty/efsw/sophist.h +++ b/src/3rdParty/efsw/sophist.h | |||
@@ -1,147 +1,147 @@ | |||
1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 | 1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 |
2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net | 2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net |
3 | ** Sophist provides portable types; you typedef/#define them to your own names | 3 | ** Sophist provides portable types; you typedef/#define them to your own names |
4 | ** | 4 | ** |
5 | ** defines: | 5 | ** defines: |
6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian | 6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian |
7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined | 7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined |
8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit | 8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit |
9 | ** | 9 | ** |
10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer | 10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer |
11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 | 11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 |
12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 | 12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 |
13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit | 13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit |
14 | ** - SOPHIST_uint64_constant(number) integer constants | 14 | ** - SOPHIST_uint64_constant(number) integer constants |
15 | ** - SOPHIST_printf_format64 - string for printf format for int64 | 15 | ** - SOPHIST_printf_format64 - string for printf format for int64 |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef __INCLUDE_SOPHIST_H__ | 18 | #ifndef __INCLUDE_SOPHIST_H__ |
19 | #define __INCLUDE_SOPHIST_H__ | 19 | #define __INCLUDE_SOPHIST_H__ |
20 | 20 | ||
21 | #define SOPHIST_compiletime_assert(name,val) \ | 21 | #define SOPHIST_compiletime_assert(name,val) \ |
22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] | 22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] |
23 | 23 | ||
24 | /* define a couple synthetic rules to make code more readable */ | 24 | /* define a couple synthetic rules to make code more readable */ |
25 | #if (defined(__sparc__) || defined(__sparc)) && \ | 25 | #if (defined(__sparc__) || defined(__sparc)) && \ |
26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) | 26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) |
27 | #define SOPHIST_sparc64 | 27 | #define SOPHIST_sparc64 |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #if (defined(linux) || defined(__linux__)) && \ | 30 | #if (defined(linux) || defined(__linux__)) && \ |
31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) | 31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) |
32 | #define SOPHIST_linux64 | 32 | #define SOPHIST_linux64 |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | /* basic types */ | 35 | /* basic types */ |
36 | typedef signed char SOPHIST_int8; | 36 | typedef signed char SOPHIST_int8; |
37 | typedef unsigned char SOPHIST_uint8; | 37 | typedef unsigned char SOPHIST_uint8; |
38 | 38 | ||
39 | typedef signed short SOPHIST_int16; | 39 | typedef signed short SOPHIST_int16; |
40 | typedef unsigned short SOPHIST_uint16; | 40 | typedef unsigned short SOPHIST_uint16; |
41 | 41 | ||
42 | #ifdef __palmos__ | 42 | #ifdef __palmos__ |
43 | typedef signed long SOPHIST_int32; | 43 | typedef signed long SOPHIST_int32; |
44 | typedef unsigned long SOPHIST_uint32; | 44 | typedef unsigned long SOPHIST_uint32; |
45 | #else | 45 | #else |
46 | typedef signed int SOPHIST_int32; | 46 | typedef signed int SOPHIST_int32; |
47 | typedef unsigned int SOPHIST_uint32; | 47 | typedef unsigned int SOPHIST_uint32; |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | #ifndef SOPHIST_NO_64 | 50 | #ifndef SOPHIST_NO_64 |
51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ | 51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ |
52 | || (defined(__alpha) && defined(__DECC)) | 52 | || (defined(__alpha) && defined(__DECC)) |
53 | 53 | ||
54 | typedef signed __int64 SOPHIST_int64; | 54 | typedef signed __int64 SOPHIST_int64; |
55 | typedef unsigned __int64 SOPHIST_uint64; | 55 | typedef unsigned __int64 SOPHIST_uint64; |
56 | #define SOPHIST_has_64 1 | 56 | #define SOPHIST_has_64 1 |
57 | #define SOPHIST_int64_constant(x) (x##i64) | 57 | #define SOPHIST_int64_constant(x) (x##i64) |
58 | #define SOPHIST_uint64_constant(x) (x##ui64) | 58 | #define SOPHIST_uint64_constant(x) (x##ui64) |
59 | #define SOPHIST_printf_format64 "I64" | 59 | #define SOPHIST_printf_format64 "I64" |
60 | 60 | ||
61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) | 61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) |
62 | 62 | ||
63 | typedef signed long SOPHIST_int64; | 63 | typedef signed long SOPHIST_int64; |
64 | typedef unsigned long SOPHIST_uint64; | 64 | typedef unsigned long SOPHIST_uint64; |
65 | 65 | ||
66 | #define SOPHIST_has_64 1 | 66 | #define SOPHIST_has_64 1 |
67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) | 67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) |
68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) | 68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) |
69 | #define SOPHIST_printf_format64 "l" | 69 | #define SOPHIST_printf_format64 "l" |
70 | 70 | ||
71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ | 71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ |
72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ | 72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ |
73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ | 73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ |
74 | || defined(_CRAYC) | 74 | || defined(_CRAYC) |
75 | 75 | ||
76 | typedef signed long long SOPHIST_int64; | 76 | typedef signed long long SOPHIST_int64; |
77 | typedef unsigned long long SOPHIST_uint64; | 77 | typedef unsigned long long SOPHIST_uint64; |
78 | 78 | ||
79 | #define SOPHIST_has_64 1 | 79 | #define SOPHIST_has_64 1 |
80 | #define SOPHIST_int64_constant(x) (x##LL) | 80 | #define SOPHIST_int64_constant(x) (x##LL) |
81 | #define SOPHIST_uint64_constant(x) (x##ULL) | 81 | #define SOPHIST_uint64_constant(x) (x##ULL) |
82 | #define SOPHIST_printf_format64 "ll" | 82 | #define SOPHIST_printf_format64 "ll" |
83 | #endif | 83 | #endif |
84 | #endif | 84 | #endif |
85 | 85 | ||
86 | #ifndef SOPHIST_has_64 | 86 | #ifndef SOPHIST_has_64 |
87 | #define SOPHIST_has_64 0 | 87 | #define SOPHIST_has_64 0 |
88 | #endif | 88 | #endif |
89 | 89 | ||
90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); | 90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); |
91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); | 91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); |
92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); | 92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); |
93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); | 93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); |
94 | 94 | ||
95 | #if SOPHIST_has_64 | 95 | #if SOPHIST_has_64 |
96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); | 96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); |
97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); | 97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | /* determine whether pointers are 64-bit */ | 100 | /* determine whether pointers are 64-bit */ |
101 | 101 | ||
102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ | 102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ |
103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ | 103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ |
104 | || defined(__64BIT__) \ | 104 | || defined(__64BIT__) \ |
105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ | 105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ |
106 | || defined(_ADDR64) || defined(_CRAYC) \ | 106 | || defined(_ADDR64) || defined(_CRAYC) \ |
107 | 107 | ||
108 | #define SOPHIST_pointer64 1 | 108 | #define SOPHIST_pointer64 1 |
109 | 109 | ||
110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); | 110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); |
111 | 111 | ||
112 | typedef SOPHIST_int64 SOPHIST_intptr; | 112 | typedef SOPHIST_int64 SOPHIST_intptr; |
113 | typedef SOPHIST_uint64 SOPHIST_uintptr; | 113 | typedef SOPHIST_uint64 SOPHIST_uintptr; |
114 | #else | 114 | #else |
115 | 115 | ||
116 | #define SOPHIST_pointer64 0 | 116 | #define SOPHIST_pointer64 0 |
117 | 117 | ||
118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); | 118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); |
119 | 119 | ||
120 | /* do we care about pointers that are only 16-bit? */ | 120 | /* do we care about pointers that are only 16-bit? */ |
121 | typedef SOPHIST_int32 SOPHIST_intptr; | 121 | typedef SOPHIST_int32 SOPHIST_intptr; |
122 | typedef SOPHIST_uint32 SOPHIST_uintptr; | 122 | typedef SOPHIST_uint32 SOPHIST_uintptr; |
123 | 123 | ||
124 | #endif | 124 | #endif |
125 | 125 | ||
126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); | 126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); |
127 | 127 | ||
128 | /* enumerate known little endian cases; fallback to big-endian */ | 128 | /* enumerate known little endian cases; fallback to big-endian */ |
129 | 129 | ||
130 | #define SOPHIST_little_endian 1 | 130 | #define SOPHIST_little_endian 1 |
131 | #define SOPHIST_big_endian 2 | 131 | #define SOPHIST_big_endian 2 |
132 | 132 | ||
133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ | 133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ |
134 | || defined(__X86) || defined(_M_IX86) \ | 134 | || defined(__X86) || defined(_M_IX86) \ |
135 | || defined(_M_X64) || defined(__x86_64__) \ | 135 | || defined(_M_X64) || defined(__x86_64__) \ |
136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ | 136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ |
137 | || defined(_M_ALPHA) \ | 137 | || defined(_M_ALPHA) \ |
138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ | 138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ |
139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ | 139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ |
140 | || defined(_WIN32_WCE) || defined(__NT__) \ | 140 | || defined(_WIN32_WCE) || defined(__NT__) \ |
141 | || defined(__MIPSEL__) | 141 | || defined(__MIPSEL__) |
142 | #define SOPHIST_endian SOPHIST_little_endian | 142 | #define SOPHIST_endian SOPHIST_little_endian |
143 | #else | 143 | #else |
144 | #define SOPHIST_endian SOPHIST_big_endian | 144 | #define SOPHIST_endian SOPHIST_big_endian |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | #endif /* __INCLUDE_SOPHIST_H__ */ | 147 | #endif /* __INCLUDE_SOPHIST_H__ */ |
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index fe6e726..945e1d7 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
@@ -167,12 +167,11 @@ std::string ExistentialOp_t::to_string(void*) const { | |||
167 | std::string TableAppendingOp_t::to_string(void*) const { | 167 | std::string TableAppendingOp_t::to_string(void*) const { |
168 | return "[]"s; | 168 | return "[]"s; |
169 | } | 169 | } |
170 | std::string PlainItem_t::to_string(void *) const { | 170 | std::string PlainItem_t::to_string(void*) const { |
171 | return {}; | 171 | return {}; |
172 | } | 172 | } |
173 | std::string GlobalOp_t::to_string(void* ud) const { | 173 | std::string GlobalOp_t::to_string(void*) const { |
174 | auto info = reinterpret_cast<YueFormat*>(ud); | 174 | return "*"s; |
175 | return info->convert(this); | ||
176 | } | 175 | } |
177 | std::string ExportDefault_t::to_string(void*) const { | 176 | std::string ExportDefault_t::to_string(void*) const { |
178 | return "default"s; | 177 | return "default"s; |
@@ -188,9 +187,17 @@ std::string ConstValue_t::to_string(void* ud) const { | |||
188 | std::string NotIn_t::to_string(void*) const { | 187 | std::string NotIn_t::to_string(void*) const { |
189 | return {}; | 188 | return {}; |
190 | } | 189 | } |
190 | std::string Break_t::to_string(void*) const { | ||
191 | return "break"s; | ||
192 | } | ||
193 | std::string Continue_t::to_string(void*) const { | ||
194 | return "continue"s; | ||
195 | } | ||
191 | std::string BreakLoop_t::to_string(void* ud) const { | 196 | std::string BreakLoop_t::to_string(void* ud) const { |
192 | auto info = reinterpret_cast<YueFormat*>(ud); | 197 | if (value) { |
193 | return info->convert(this); | 198 | return type->to_string(ud) + ' ' + value->to_string(ud); |
199 | } | ||
200 | return type->to_string(ud); | ||
194 | } | 201 | } |
195 | std::string YueLineComment_t::to_string(void* ud) const { | 202 | std::string YueLineComment_t::to_string(void* ud) const { |
196 | auto info = reinterpret_cast<YueFormat*>(ud); | 203 | auto info = reinterpret_cast<YueFormat*>(ud); |
@@ -297,6 +304,17 @@ std::string ImportAs_t::to_string(void* ud) const { | |||
297 | } | 304 | } |
298 | return join(temp, " "s); | 305 | return join(temp, " "s); |
299 | } | 306 | } |
307 | std::string ImportGlobal_t::to_string(void* ud) const { | ||
308 | str_list temp; | ||
309 | for (auto seg : segs.objects()) { | ||
310 | temp.emplace_back(seg->to_string(ud)); | ||
311 | } | ||
312 | auto item = join(temp, "."s); | ||
313 | if (target) { | ||
314 | return item + " as "s + target->to_string(ud); | ||
315 | } | ||
316 | return item; | ||
317 | } | ||
300 | std::string Import_t::to_string(void* ud) const { | 318 | std::string Import_t::to_string(void* ud) const { |
301 | if (ast_is<FromImport_t>(content)) { | 319 | if (ast_is<FromImport_t>(content)) { |
302 | return content->to_string(ud); | 320 | return content->to_string(ud); |
@@ -324,6 +342,12 @@ std::string Backcall_t::to_string(void* ud) const { | |||
324 | temp.emplace_back(value->to_string(ud)); | 342 | temp.emplace_back(value->to_string(ud)); |
325 | return join(temp, " "sv); | 343 | return join(temp, " "sv); |
326 | } | 344 | } |
345 | std::string SubBackcall_t::to_string(void* ud) const { | ||
346 | str_list temp; | ||
347 | temp.emplace_back(arrow->to_string(ud)); | ||
348 | temp.emplace_back(value->to_string(ud)); | ||
349 | return join(temp, " "sv); | ||
350 | } | ||
327 | std::string PipeBody_t::to_string(void* ud) const { | 351 | std::string PipeBody_t::to_string(void* ud) const { |
328 | auto info = reinterpret_cast<YueFormat*>(ud); | 352 | auto info = reinterpret_cast<YueFormat*>(ud); |
329 | str_list temp; | 353 | str_list temp; |
@@ -359,8 +383,8 @@ std::string With_t::to_string(void* ud) const { | |||
359 | str_list temp{ | 383 | str_list temp{ |
360 | eop ? "with?"s : "with"s, | 384 | eop ? "with?"s : "with"s, |
361 | valueList->to_string(ud)}; | 385 | valueList->to_string(ud)}; |
362 | if (assigns) { | 386 | if (assign) { |
363 | temp.push_back(assigns->to_string(ud)); | 387 | temp.push_back(':' + assign->to_string(ud)); |
364 | } | 388 | } |
365 | if (body.is<Statement_t>()) { | 389 | if (body.is<Statement_t>()) { |
366 | return join(temp, " "sv) + " do "s + body->to_string(ud); | 390 | return join(temp, " "sv) + " do "s + body->to_string(ud); |
@@ -406,6 +430,9 @@ std::string SwitchCase_t::to_string(void* ud) const { | |||
406 | std::string Switch_t::to_string(void* ud) const { | 430 | std::string Switch_t::to_string(void* ud) const { |
407 | auto info = reinterpret_cast<YueFormat*>(ud); | 431 | auto info = reinterpret_cast<YueFormat*>(ud); |
408 | str_list temp{"switch "s + target->to_string(ud)}; | 432 | str_list temp{"switch "s + target->to_string(ud)}; |
433 | if (assignment) { | ||
434 | temp.back().append(assignment->to_string(ud)); | ||
435 | } | ||
409 | info->pushScope(); | 436 | info->pushScope(); |
410 | for (auto branch : branches.objects()) { | 437 | for (auto branch : branches.objects()) { |
411 | temp.emplace_back(info->ind() + branch->to_string(ud)); | 438 | temp.emplace_back(info->ind() + branch->to_string(ud)); |
@@ -449,41 +476,75 @@ std::string If_t::to_string(void* ud) const { | |||
449 | temp.back() += " then"s; | 476 | temp.back() += " then"s; |
450 | } | 477 | } |
451 | ++it; | 478 | ++it; |
452 | bool condition = true; | 479 | enum class NType { |
480 | Cond, | ||
481 | Stat, | ||
482 | Block | ||
483 | }; | ||
484 | NType lastType = NType::Cond; | ||
453 | for (; it != nodes.objects().end(); ++it) { | 485 | for (; it != nodes.objects().end(); ++it) { |
454 | auto node = *it; | 486 | auto node = *it; |
455 | switch (node->get_id()) { | 487 | switch (node->get_id()) { |
456 | case id<IfCond_t>(): | 488 | case id<IfCond_t>(): |
457 | temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); | 489 | temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); |
458 | condition = true; | 490 | lastType = NType::Cond; |
459 | break; | 491 | break; |
460 | case id<Statement_t>(): { | 492 | case id<Statement_t>(): { |
461 | if (condition) { | 493 | switch (lastType) { |
462 | temp.back() += " then "s + node->to_string(ud); | 494 | case NType::Cond: |
463 | } else { | 495 | temp.back() += " then "s + node->to_string(ud); |
464 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | 496 | break; |
497 | case NType::Stat: | ||
498 | if (temp.back().back() == '\n') { | ||
499 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | ||
500 | } else { | ||
501 | temp.back() += " else "s + node->to_string(ud); | ||
502 | } | ||
503 | break; | ||
504 | case NType::Block: | ||
505 | temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); | ||
506 | break; | ||
465 | } | 507 | } |
466 | condition = false; | 508 | lastType = NType::Stat; |
467 | break; | 509 | break; |
468 | } | 510 | } |
469 | case id<Block_t>(): { | 511 | case id<Block_t>(): { |
470 | if (condition) { | 512 | switch (lastType) { |
471 | info->pushScope(); | 513 | case NType::Cond: { |
472 | temp.emplace_back(node->to_string(ud)); | 514 | info->pushScope(); |
473 | if (temp.back().empty()) { | 515 | temp.emplace_back(node->to_string(ud)); |
474 | temp.back() = info->ind() + "--"s; | 516 | if (temp.back().empty()) { |
517 | temp.back() = info->ind() + "--"s; | ||
518 | } | ||
519 | info->popScope(); | ||
520 | break; | ||
521 | } | ||
522 | case NType::Stat: { | ||
523 | if (temp.back().back() == '\n') { | ||
524 | temp.emplace_back(info->ind() + "else"s); | ||
525 | } else { | ||
526 | temp.back() += " else"s; | ||
527 | } | ||
528 | info->pushScope(); | ||
529 | temp.emplace_back(node->to_string(ud)); | ||
530 | if (temp.back().empty()) { | ||
531 | temp.back() = info->ind() + "--"s; | ||
532 | } | ||
533 | info->popScope(); | ||
534 | break; | ||
475 | } | 535 | } |
476 | info->popScope(); | 536 | case NType::Block: { |
477 | } else { | 537 | temp.emplace_back(info->ind() + "else"s); |
478 | temp.emplace_back(info->ind() + "else"s); | 538 | info->pushScope(); |
479 | info->pushScope(); | 539 | temp.emplace_back(node->to_string(ud)); |
480 | temp.emplace_back(node->to_string(ud)); | 540 | if (temp.back().empty()) { |
481 | if (temp.back().empty()) { | 541 | temp.back() = info->ind() + "--"s; |
482 | temp.back() = info->ind() + "--"s; | 542 | } |
543 | info->popScope(); | ||
544 | break; | ||
483 | } | 545 | } |
484 | info->popScope(); | ||
485 | } | 546 | } |
486 | condition = false; | 547 | lastType = NType::Block; |
487 | break; | 548 | break; |
488 | } | 549 | } |
489 | } | 550 | } |
@@ -511,10 +572,10 @@ std::string While_t::to_string(void* ud) const { | |||
511 | } | 572 | } |
512 | std::string Repeat_t::to_string(void* ud) const { | 573 | std::string Repeat_t::to_string(void* ud) const { |
513 | auto info = reinterpret_cast<YueFormat*>(ud); | 574 | auto info = reinterpret_cast<YueFormat*>(ud); |
514 | str_list temp; | 575 | if (body.is<Statement_t>()) { |
515 | if (body->content.is<Statement_t>()) { | 576 | return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud); |
516 | temp.emplace_back("repeat "s + body->to_string(ud)); | ||
517 | } else { | 577 | } else { |
578 | str_list temp; | ||
518 | temp.emplace_back("repeat"s); | 579 | temp.emplace_back("repeat"s); |
519 | info->pushScope(); | 580 | info->pushScope(); |
520 | temp.emplace_back(body->to_string(ud)); | 581 | temp.emplace_back(body->to_string(ud)); |
@@ -522,9 +583,9 @@ std::string Repeat_t::to_string(void* ud) const { | |||
522 | temp.back() = info->ind() + "--"s; | 583 | temp.back() = info->ind() + "--"s; |
523 | } | 584 | } |
524 | info->popScope(); | 585 | info->popScope(); |
586 | temp.emplace_back(info->ind() + "until "s + condition->to_string(ud)); | ||
587 | return join(temp, "\n"sv); | ||
525 | } | 588 | } |
526 | temp.emplace_back(info->ind() + "until "s + condition->to_string(ud)); | ||
527 | return join(temp, "\n"sv); | ||
528 | } | 589 | } |
529 | std::string ForStepValue_t::to_string(void* ud) const { | 590 | std::string ForStepValue_t::to_string(void* ud) const { |
530 | return value->to_string(ud); | 591 | return value->to_string(ud); |
@@ -596,10 +657,13 @@ std::string CatchBlock_t::to_string(void* ud) const { | |||
596 | std::string Try_t::to_string(void* ud) const { | 657 | std::string Try_t::to_string(void* ud) const { |
597 | auto info = reinterpret_cast<YueFormat*>(ud); | 658 | auto info = reinterpret_cast<YueFormat*>(ud); |
598 | str_list temp; | 659 | str_list temp; |
660 | temp.emplace_back("try"s); | ||
661 | if (eop) { | ||
662 | temp.back() += eop->to_string(ud); | ||
663 | } | ||
599 | if (func.is<Exp_t>()) { | 664 | if (func.is<Exp_t>()) { |
600 | temp.emplace_back("try "s + func->to_string(ud)); | 665 | temp.back() += (" "s + func->to_string(ud)); |
601 | } else { | 666 | } else { |
602 | temp.emplace_back("try"s); | ||
603 | info->pushScope(); | 667 | info->pushScope(); |
604 | temp.emplace_back(func->to_string(ud)); | 668 | temp.emplace_back(func->to_string(ud)); |
605 | if (temp.back().empty()) { | 669 | if (temp.back().empty()) { |
@@ -851,6 +915,12 @@ std::string Exp_t::to_string(void* ud) const { | |||
851 | } | 915 | } |
852 | return join(temp, " "sv); | 916 | return join(temp, " "sv); |
853 | } | 917 | } |
918 | std::string ReversedIndex_t::to_string(void* ud) const { | ||
919 | if (modifier) { | ||
920 | return "[# - "s + modifier->to_string(ud) + ']'; | ||
921 | } | ||
922 | return "[#]"s; | ||
923 | } | ||
854 | std::string Callable_t::to_string(void* ud) const { | 924 | std::string Callable_t::to_string(void* ud) const { |
855 | return item->to_string(ud); | 925 | return item->to_string(ud); |
856 | } | 926 | } |
@@ -937,6 +1007,51 @@ std::string DoubleString_t::to_string(void* ud) const { | |||
937 | } | 1007 | } |
938 | return '"' + join(temp) + '"'; | 1008 | return '"' + join(temp) + '"'; |
939 | } | 1009 | } |
1010 | std::string YAMLIndent_t::to_string(void* ud) const { | ||
1011 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
1012 | return info->convert(this); | ||
1013 | } | ||
1014 | std::string YAMLLineInner_t::to_string(void* ud) const { | ||
1015 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
1016 | return info->convert(this); | ||
1017 | } | ||
1018 | std::string YAMLLineContent_t::to_string(void* ud) const { | ||
1019 | if (content.is<Exp_t>()) { | ||
1020 | return "#{"s + content->to_string(ud) + '}'; | ||
1021 | } | ||
1022 | return content->to_string(ud); | ||
1023 | } | ||
1024 | std::string YAMLLine_t::to_string(void* ud) const { | ||
1025 | str_list temp; | ||
1026 | for (auto seg : segments.objects()) { | ||
1027 | temp.emplace_back(seg->to_string(ud)); | ||
1028 | } | ||
1029 | return join(temp); | ||
1030 | } | ||
1031 | std::string YAMLMultiline_t::to_string(void* ud) const { | ||
1032 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
1033 | int currentIndent = info->indent; | ||
1034 | str_list temp; | ||
1035 | int lastIndent = -1; | ||
1036 | for (auto line_ : lines.objects()) { | ||
1037 | auto line = static_cast<YAMLLine_t*>(line_); | ||
1038 | auto indent = line->indent->to_string(ud); | ||
1039 | int ind = 0; | ||
1040 | for (auto c : indent) { | ||
1041 | if (c == ' ') ind++; | ||
1042 | if (c == '\t') ind += 4; | ||
1043 | } | ||
1044 | if (lastIndent < ind) { | ||
1045 | info->pushScope(); | ||
1046 | } else if (lastIndent > ind) { | ||
1047 | info->popScope(); | ||
1048 | } | ||
1049 | lastIndent = ind; | ||
1050 | temp.emplace_back(indent + line->to_string(ud)); | ||
1051 | } | ||
1052 | info->indent = currentIndent; | ||
1053 | return "|\n" + join(temp, "\n"sv) + '\n'; | ||
1054 | } | ||
940 | std::string String_t::to_string(void* ud) const { | 1055 | std::string String_t::to_string(void* ud) const { |
941 | return str->to_string(ud); | 1056 | return str->to_string(ud); |
942 | } | 1057 | } |
@@ -1125,7 +1240,7 @@ std::string ClassDecl_t::to_string(void* ud) const { | |||
1125 | return line; | 1240 | return line; |
1126 | } | 1241 | } |
1127 | std::string GlobalValues_t::to_string(void* ud) const { | 1242 | std::string GlobalValues_t::to_string(void* ud) const { |
1128 | auto line = nameList->to_string(ud); | 1243 | std::string line = nameList->to_string(ud); |
1129 | if (valueList) { | 1244 | if (valueList) { |
1130 | if (valueList.is<TableBlock_t>()) { | 1245 | if (valueList.is<TableBlock_t>()) { |
1131 | line += " =\n"s + valueList->to_string(ud); | 1246 | line += " =\n"s + valueList->to_string(ud); |
@@ -1136,7 +1251,7 @@ std::string GlobalValues_t::to_string(void* ud) const { | |||
1136 | return line; | 1251 | return line; |
1137 | } | 1252 | } |
1138 | std::string Global_t::to_string(void* ud) const { | 1253 | std::string Global_t::to_string(void* ud) const { |
1139 | return "global "s + item->to_string(ud); | 1254 | return "global "s + (constAttrib ? "const "s : ""s) + item->to_string(ud); |
1140 | } | 1255 | } |
1141 | std::string Export_t::to_string(void* ud) const { | 1256 | std::string Export_t::to_string(void* ud) const { |
1142 | auto line = "export"s; | 1257 | auto line = "export"s; |
@@ -1235,6 +1350,9 @@ std::string FnArgDef_t::to_string(void* ud) const { | |||
1235 | if (op) { | 1350 | if (op) { |
1236 | line += op->to_string(ud); | 1351 | line += op->to_string(ud); |
1237 | } | 1352 | } |
1353 | if (label) { | ||
1354 | line += '`' + label->to_string(ud); | ||
1355 | } | ||
1238 | if (defaultValue) { | 1356 | if (defaultValue) { |
1239 | line += " = "s + defaultValue->to_string(ud); | 1357 | line += " = "s + defaultValue->to_string(ud); |
1240 | } | 1358 | } |
@@ -1257,6 +1375,9 @@ std::string FnArgDefList_t::to_string(void* ud) const { | |||
1257 | } | 1375 | } |
1258 | if (varArg) { | 1376 | if (varArg) { |
1259 | temp.emplace_back(info->ind() + varArg->to_string(ud)); | 1377 | temp.emplace_back(info->ind() + varArg->to_string(ud)); |
1378 | if (label) { | ||
1379 | temp.back().append('`' + label->to_string(ud)); | ||
1380 | } | ||
1260 | } | 1381 | } |
1261 | return join(temp, "\n"sv); | 1382 | return join(temp, "\n"sv); |
1262 | } else { | 1383 | } else { |
@@ -1265,6 +1386,9 @@ std::string FnArgDefList_t::to_string(void* ud) const { | |||
1265 | } | 1386 | } |
1266 | if (varArg) { | 1387 | if (varArg) { |
1267 | temp.emplace_back(varArg->to_string(ud)); | 1388 | temp.emplace_back(varArg->to_string(ud)); |
1389 | if (label) { | ||
1390 | temp.back().append('`' + label->to_string(ud)); | ||
1391 | } | ||
1268 | } | 1392 | } |
1269 | return join(temp, ", "sv); | 1393 | return join(temp, ", "sv); |
1270 | } | 1394 | } |
@@ -1546,3 +1670,4 @@ std::string File_t::to_string(void* ud) const { | |||
1546 | } // namespace yue | 1670 | } // namespace yue |
1547 | 1671 | ||
1548 | } // namespace parserlib | 1672 | } // namespace parserlib |
1673 | |||
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index e670126..1937eb8 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -233,8 +233,15 @@ AST_NODE(ImportAs) | |||
233 | AST_MEMBER(ImportAs, &literal, &target) | 233 | AST_MEMBER(ImportAs, &literal, &target) |
234 | AST_END(ImportAs) | 234 | AST_END(ImportAs) |
235 | 235 | ||
236 | AST_NODE(ImportGlobal) | ||
237 | ast_ptr<true, Seperator_t> sep; | ||
238 | ast_list<true, UnicodeName_t> segs; | ||
239 | ast_ptr<false, Variable_t> target; | ||
240 | AST_MEMBER(ImportGlobal, &sep, &segs, &target) | ||
241 | AST_END(ImportGlobal) | ||
242 | |||
236 | AST_NODE(Import) | 243 | AST_NODE(Import) |
237 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; | 244 | ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content; |
238 | AST_MEMBER(Import, &content) | 245 | AST_MEMBER(Import, &content) |
239 | AST_END(Import) | 246 | AST_END(Import) |
240 | 247 | ||
@@ -273,6 +280,8 @@ AST_NODE(ExpList) | |||
273 | ast_ptr<true, Seperator_t> sep; | 280 | ast_ptr<true, Seperator_t> sep; |
274 | ast_list<true, Exp_t> exprs; | 281 | ast_list<true, Exp_t> exprs; |
275 | AST_MEMBER(ExpList, &sep, &exprs) | 282 | AST_MEMBER(ExpList, &sep, &exprs) |
283 | bool followStmtProcessed = false; | ||
284 | Statement_t* followStmt = nullptr; | ||
276 | AST_END(ExpList) | 285 | AST_END(ExpList) |
277 | 286 | ||
278 | AST_NODE(Return) | 287 | AST_NODE(Return) |
@@ -285,9 +294,9 @@ AST_END(Return) | |||
285 | AST_NODE(With) | 294 | AST_NODE(With) |
286 | ast_ptr<false, ExistentialOp_t> eop; | 295 | ast_ptr<false, ExistentialOp_t> eop; |
287 | ast_ptr<true, ExpList_t> valueList; | 296 | ast_ptr<true, ExpList_t> valueList; |
288 | ast_ptr<false, Assign_t> assigns; | 297 | ast_ptr<false, Assign_t> assign; |
289 | ast_sel<true, Block_t, Statement_t> body; | 298 | ast_sel<true, Block_t, Statement_t> body; |
290 | AST_MEMBER(With, &eop, &valueList, &assigns, &body) | 299 | AST_MEMBER(With, &eop, &valueList, &assign, &body) |
291 | AST_END(With) | 300 | AST_END(With) |
292 | 301 | ||
293 | AST_NODE(SwitchList) | 302 | AST_NODE(SwitchList) |
@@ -302,20 +311,21 @@ AST_NODE(SwitchCase) | |||
302 | AST_MEMBER(SwitchCase, &condition, &body) | 311 | AST_MEMBER(SwitchCase, &condition, &body) |
303 | AST_END(SwitchCase) | 312 | AST_END(SwitchCase) |
304 | 313 | ||
314 | AST_NODE(Assignment) | ||
315 | ast_ptr<false, ExpList_t> expList; | ||
316 | ast_ptr<true, Assign_t> assign; | ||
317 | AST_MEMBER(Assignment, &expList, &assign) | ||
318 | AST_END(Assignment) | ||
319 | |||
305 | AST_NODE(Switch) | 320 | AST_NODE(Switch) |
306 | ast_ptr<true, Exp_t> target; | 321 | ast_ptr<true, Exp_t> target; |
322 | ast_ptr<false, Assignment_t> assignment; | ||
307 | ast_ptr<true, Seperator_t> sep; | 323 | ast_ptr<true, Seperator_t> sep; |
308 | ast_list<true, SwitchCase_t> branches; | 324 | ast_list<true, SwitchCase_t> branches; |
309 | ast_sel<false, Block_t, Statement_t> lastBranch; | 325 | ast_sel<false, Block_t, Statement_t> lastBranch; |
310 | AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) | 326 | AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch) |
311 | AST_END(Switch) | 327 | AST_END(Switch) |
312 | 328 | ||
313 | AST_NODE(Assignment) | ||
314 | ast_ptr<false, ExpList_t> expList; | ||
315 | ast_ptr<true, Assign_t> assign; | ||
316 | AST_MEMBER(Assignment, &expList, &assign) | ||
317 | AST_END(Assignment) | ||
318 | |||
319 | AST_NODE(IfCond) | 329 | AST_NODE(IfCond) |
320 | ast_ptr<true, Exp_t> condition; | 330 | ast_ptr<true, Exp_t> condition; |
321 | ast_ptr<false, Assignment_t> assignment; | 331 | ast_ptr<false, Assignment_t> assignment; |
@@ -343,7 +353,7 @@ AST_NODE(While) | |||
343 | AST_END(While) | 353 | AST_END(While) |
344 | 354 | ||
345 | AST_NODE(Repeat) | 355 | AST_NODE(Repeat) |
346 | ast_ptr<true, Body_t> body; | 356 | ast_sel<true, Block_t, Statement_t> body; |
347 | ast_ptr<true, Exp_t> condition; | 357 | ast_ptr<true, Exp_t> condition; |
348 | AST_MEMBER(Repeat, &body, &condition) | 358 | AST_MEMBER(Repeat, &body, &condition) |
349 | AST_END(Repeat) | 359 | AST_END(Repeat) |
@@ -381,9 +391,10 @@ AST_NODE(CatchBlock) | |||
381 | AST_END(CatchBlock) | 391 | AST_END(CatchBlock) |
382 | 392 | ||
383 | AST_NODE(Try) | 393 | AST_NODE(Try) |
394 | ast_ptr<false, ExistentialOp_t> eop; | ||
384 | ast_sel<true, Block_t, Exp_t> func; | 395 | ast_sel<true, Block_t, Exp_t> func; |
385 | ast_ptr<false, CatchBlock_t> catchBlock; | 396 | ast_ptr<false, CatchBlock_t> catchBlock; |
386 | AST_MEMBER(Try, &func, &catchBlock) | 397 | AST_MEMBER(Try, &eop, &func, &catchBlock) |
387 | AST_END(Try) | 398 | AST_END(Try) |
388 | 399 | ||
389 | AST_NODE(Comprehension) | 400 | AST_NODE(Comprehension) |
@@ -547,8 +558,8 @@ AST_NODE(SimpleValue) | |||
547 | ast_sel<true, | 558 | ast_sel<true, |
548 | TableLit_t, ConstValue_t, | 559 | TableLit_t, ConstValue_t, |
549 | If_t, Switch_t, With_t, ClassDecl_t, | 560 | If_t, Switch_t, With_t, ClassDecl_t, |
550 | ForEach_t, For_t, While_t, Do_t, Try_t, | 561 | ForEach_t, For_t, While_t, Repeat_t, |
551 | UnaryValue_t, | 562 | Do_t, Try_t, UnaryValue_t, |
552 | TblComprehension_t, Comprehension_t, | 563 | TblComprehension_t, Comprehension_t, |
553 | FunLit_t, Num_t, VarArg_t> value; | 564 | FunLit_t, Num_t, VarArg_t> value; |
554 | AST_MEMBER(SimpleValue, &value) | 565 | AST_MEMBER(SimpleValue, &value) |
@@ -587,8 +598,31 @@ AST_NODE(DoubleString) | |||
587 | AST_MEMBER(DoubleString, &sep, &segments) | 598 | AST_MEMBER(DoubleString, &sep, &segments) |
588 | AST_END(DoubleString) | 599 | AST_END(DoubleString) |
589 | 600 | ||
601 | AST_LEAF(YAMLIndent) | ||
602 | AST_END(YAMLIndent) | ||
603 | |||
604 | AST_LEAF(YAMLLineInner) | ||
605 | AST_END(YAMLLineInner) | ||
606 | |||
607 | AST_NODE(YAMLLineContent) | ||
608 | ast_sel<true, YAMLLineInner_t, Exp_t> content; | ||
609 | AST_MEMBER(YAMLLineContent, &content) | ||
610 | AST_END(YAMLLineContent) | ||
611 | |||
612 | AST_NODE(YAMLLine) | ||
613 | ast_ptr<true, YAMLIndent_t> indent; | ||
614 | ast_list<true, YAMLLineContent_t> segments; | ||
615 | AST_MEMBER(YAMLLine, &indent, &segments) | ||
616 | AST_END(YAMLLine) | ||
617 | |||
618 | AST_NODE(YAMLMultiline) | ||
619 | ast_ptr<true, Seperator_t> sep; | ||
620 | ast_list<true, YAMLLine_t> lines; | ||
621 | AST_MEMBER(YAMLMultiline, &sep, &lines) | ||
622 | AST_END(YAMLMultiline) | ||
623 | |||
590 | AST_NODE(String) | 624 | AST_NODE(String) |
591 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; | 625 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str; |
592 | AST_MEMBER(String, &str) | 626 | AST_MEMBER(String, &str) |
593 | AST_END(String) | 627 | AST_END(String) |
594 | 628 | ||
@@ -620,6 +654,7 @@ AST_END(Slice) | |||
620 | 654 | ||
621 | AST_NODE(Parens) | 655 | AST_NODE(Parens) |
622 | ast_ptr<true, Exp_t> expr; | 656 | ast_ptr<true, Exp_t> expr; |
657 | bool extra = false; | ||
623 | AST_MEMBER(Parens, &expr) | 658 | AST_MEMBER(Parens, &expr) |
624 | AST_END(Parens) | 659 | AST_END(Parens) |
625 | 660 | ||
@@ -638,9 +673,14 @@ AST_END(TableAppendingOp) | |||
638 | AST_LEAF(PlainItem) | 673 | AST_LEAF(PlainItem) |
639 | AST_END(PlainItem) | 674 | AST_END(PlainItem) |
640 | 675 | ||
676 | AST_NODE(ReversedIndex) | ||
677 | ast_ptr<false, Exp_t> modifier; | ||
678 | AST_MEMBER(ReversedIndex, &modifier) | ||
679 | AST_END(ReversedIndex) | ||
680 | |||
641 | AST_NODE(ChainValue) | 681 | AST_NODE(ChainValue) |
642 | ast_ptr<true, Seperator_t> sep; | 682 | ast_ptr<true, Seperator_t> sep; |
643 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, | 683 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t, |
644 | /*non-syntax-rule*/ PlainItem_t> items; | 684 | /*non-syntax-rule*/ PlainItem_t> items; |
645 | AST_MEMBER(ChainValue, &sep, &items) | 685 | AST_MEMBER(ChainValue, &sep, &items) |
646 | AST_END(ChainValue) | 686 | AST_END(ChainValue) |
@@ -724,8 +764,9 @@ AST_LEAF(GlobalOp) | |||
724 | AST_END(GlobalOp) | 764 | AST_END(GlobalOp) |
725 | 765 | ||
726 | AST_NODE(Global) | 766 | AST_NODE(Global) |
767 | ast_ptr<false, ConstAttrib_t> constAttrib; | ||
727 | ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; | 768 | ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; |
728 | AST_MEMBER(Global, &item) | 769 | AST_MEMBER(Global, &constAttrib, &item) |
729 | AST_END(Global) | 770 | AST_END(Global) |
730 | 771 | ||
731 | AST_LEAF(ExportDefault) | 772 | AST_LEAF(ExportDefault) |
@@ -741,15 +782,17 @@ AST_END(Export) | |||
741 | AST_NODE(FnArgDef) | 782 | AST_NODE(FnArgDef) |
742 | ast_sel<true, Variable_t, SelfItem_t> name; | 783 | ast_sel<true, Variable_t, SelfItem_t> name; |
743 | ast_ptr<false, ExistentialOp_t> op; | 784 | ast_ptr<false, ExistentialOp_t> op; |
785 | ast_ptr<false, Name_t> label; | ||
744 | ast_ptr<false, Exp_t> defaultValue; | 786 | ast_ptr<false, Exp_t> defaultValue; |
745 | AST_MEMBER(FnArgDef, &name, &op, &defaultValue) | 787 | AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue) |
746 | AST_END(FnArgDef) | 788 | AST_END(FnArgDef) |
747 | 789 | ||
748 | AST_NODE(FnArgDefList) | 790 | AST_NODE(FnArgDefList) |
749 | ast_ptr<true, Seperator_t> sep; | 791 | ast_ptr<true, Seperator_t> sep; |
750 | ast_list<false, FnArgDef_t> definitions; | 792 | ast_list<false, FnArgDef_t> definitions; |
751 | ast_ptr<false, VarArg_t> varArg; | 793 | ast_ptr<false, VarArg_t> varArg; |
752 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) | 794 | ast_ptr<false, Name_t> label; |
795 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label) | ||
753 | AST_END(FnArgDefList) | 796 | AST_END(FnArgDefList) |
754 | 797 | ||
755 | AST_NODE(OuterVarShadow) | 798 | AST_NODE(OuterVarShadow) |
@@ -837,9 +880,15 @@ AST_NODE(UnaryExp) | |||
837 | AST_MEMBER(UnaryExp, &ops, &expos, &inExp) | 880 | AST_MEMBER(UnaryExp, &ops, &expos, &inExp) |
838 | AST_END(UnaryExp) | 881 | AST_END(UnaryExp) |
839 | 882 | ||
883 | AST_NODE(SubBackcall) | ||
884 | ast_ptr<true, FnArrowBack_t> arrow; | ||
885 | ast_ptr<true, ChainValue_t> value; | ||
886 | AST_MEMBER(SubBackcall, &arrow, &value) | ||
887 | AST_END(SubBackcall) | ||
888 | |||
840 | AST_NODE(ExpListAssign) | 889 | AST_NODE(ExpListAssign) |
841 | ast_ptr<true, ExpList_t> expList; | 890 | ast_ptr<true, ExpList_t> expList; |
842 | ast_sel<false, Update_t, Assign_t> action; | 891 | ast_sel<false, Update_t, Assign_t, SubBackcall_t> action; |
843 | AST_MEMBER(ExpListAssign, &expList, &action) | 892 | AST_MEMBER(ExpListAssign, &expList, &action) |
844 | AST_END(ExpListAssign) | 893 | AST_END(ExpListAssign) |
845 | 894 | ||
@@ -855,7 +904,17 @@ AST_NODE(WhileLine) | |||
855 | AST_MEMBER(WhileLine, &type, &condition) | 904 | AST_MEMBER(WhileLine, &type, &condition) |
856 | AST_END(WhileLine) | 905 | AST_END(WhileLine) |
857 | 906 | ||
858 | AST_LEAF(BreakLoop) | 907 | AST_LEAF(Break) |
908 | AST_END(Break) | ||
909 | |||
910 | AST_LEAF(Continue) | ||
911 | AST_END(Continue) | ||
912 | |||
913 | AST_NODE(BreakLoop) | ||
914 | ast_sel<true, Break_t, Continue_t> type; | ||
915 | ast_ptr<false, Exp_t> value; | ||
916 | AST_MEMBER(BreakLoop, &type, &value) | ||
917 | std::string varBWV; | ||
859 | AST_END(BreakLoop) | 918 | AST_END(BreakLoop) |
860 | 919 | ||
861 | AST_NODE(PipeBody) | 920 | AST_NODE(PipeBody) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index a2a1864..d676750 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -7,9 +7,12 @@ The above copyright notice and this permission notice shall be included in all c | |||
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ |
8 | 8 | ||
9 | #include <chrono> | 9 | #include <chrono> |
10 | #include <cmath> | ||
11 | #include <iomanip> | ||
10 | #include <memory> | 12 | #include <memory> |
11 | #include <optional> | 13 | #include <optional> |
12 | #include <set> | 14 | #include <set> |
15 | #include <sstream> | ||
13 | #include <stack> | 16 | #include <stack> |
14 | #include <string> | 17 | #include <string> |
15 | #include <unordered_map> | 18 | #include <unordered_map> |
@@ -75,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
76 | }; | 79 | }; |
77 | 80 | ||
78 | const std::string_view version = "0.27.3"sv; | 81 | const std::string_view version = "0.29.3"sv; |
79 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
80 | 83 | ||
81 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
@@ -162,12 +165,12 @@ public: | |||
162 | double compileTime = 0.0; | 165 | double compileTime = 0.0; |
163 | if (config.profiling) { | 166 | if (config.profiling) { |
164 | auto start = std::chrono::high_resolution_clock::now(); | 167 | auto start = std::chrono::high_resolution_clock::now(); |
165 | _info = _parser.parse<File_t>(codes); | 168 | _info = _parser.parse<File_t>(codes, config.lax); |
166 | auto stop = std::chrono::high_resolution_clock::now(); | 169 | auto stop = std::chrono::high_resolution_clock::now(); |
167 | std::chrono::duration<double> diff = stop - start; | 170 | std::chrono::duration<double> diff = stop - start; |
168 | parseTime = diff.count(); | 171 | parseTime = diff.count(); |
169 | } else { | 172 | } else { |
170 | _info = _parser.parse<File_t>(codes); | 173 | _info = _parser.parse<File_t>(codes, config.lax); |
171 | } | 174 | } |
172 | std::unique_ptr<GlobalVars> globals; | 175 | std::unique_ptr<GlobalVars> globals; |
173 | std::unique_ptr<Options> options; | 176 | std::unique_ptr<Options> options; |
@@ -426,8 +429,9 @@ private: | |||
426 | }; | 429 | }; |
427 | enum class VarType { | 430 | enum class VarType { |
428 | Local = 0, | 431 | Local = 0, |
429 | Const = 1, | 432 | LocalConst = 1, |
430 | Global = 2 | 433 | Global = 2, |
434 | GlobalConst = 3 | ||
431 | }; | 435 | }; |
432 | struct Scope { | 436 | struct Scope { |
433 | GlobalMode mode = GlobalMode::None; | 437 | GlobalMode mode = GlobalMode::None; |
@@ -555,7 +559,7 @@ private: | |||
555 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | 559 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { |
556 | auto vars = it->vars.get(); | 560 | auto vars = it->vars.get(); |
557 | auto vit = vars->find(name); | 561 | auto vit = vars->find(name); |
558 | if (vit != vars->end() && vit->second != VarType::Global) { | 562 | if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) { |
559 | local = true; | 563 | local = true; |
560 | break; | 564 | break; |
561 | } | 565 | } |
@@ -568,7 +572,7 @@ private: | |||
568 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | 572 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { |
569 | auto vars = it->vars.get(); | 573 | auto vars = it->vars.get(); |
570 | auto vit = vars->find(name); | 574 | auto vit = vars->find(name); |
571 | if (vit != vars->end() && vit->second == VarType::Global) { | 575 | if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) { |
572 | global = true; | 576 | global = true; |
573 | break; | 577 | break; |
574 | } | 578 | } |
@@ -590,7 +594,7 @@ private: | |||
590 | auto vars = it->vars.get(); | 594 | auto vars = it->vars.get(); |
591 | auto vit = vars->find(name); | 595 | auto vit = vars->find(name); |
592 | if (vit != vars->end()) { | 596 | if (vit != vars->end()) { |
593 | isConst = (vit->second == VarType::Const); | 597 | isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst); |
594 | break; | 598 | break; |
595 | } | 599 | } |
596 | if (checkShadowScopeOnly && it->allows) break; | 600 | if (checkShadowScopeOnly && it->allows) break; |
@@ -871,9 +875,9 @@ private: | |||
871 | return false; | 875 | return false; |
872 | } | 876 | } |
873 | 877 | ||
874 | void markVarConst(const std::string& name) { | 878 | void markVarLocalConst(const std::string& name) { |
875 | auto& scope = _scopes.back(); | 879 | auto& scope = _scopes.back(); |
876 | scope.vars->insert_or_assign(name, VarType::Const); | 880 | scope.vars->insert_or_assign(name, VarType::LocalConst); |
877 | } | 881 | } |
878 | 882 | ||
879 | void markVarShadowed() { | 883 | void markVarShadowed() { |
@@ -892,6 +896,11 @@ private: | |||
892 | scope.vars->insert_or_assign(name, VarType::Global); | 896 | scope.vars->insert_or_assign(name, VarType::Global); |
893 | } | 897 | } |
894 | 898 | ||
899 | void markVarGlobalConst(const std::string& name) { | ||
900 | auto& scope = _scopes.back(); | ||
901 | scope.vars->insert_or_assign(name, VarType::GlobalConst); | ||
902 | } | ||
903 | |||
895 | void addToAllowList(const std::string& name) { | 904 | void addToAllowList(const std::string& name) { |
896 | auto& scope = _scopes.back(); | 905 | auto& scope = _scopes.back(); |
897 | scope.allows->insert(name); | 906 | scope.allows->insert(name); |
@@ -1080,8 +1089,8 @@ private: | |||
1080 | if (unary->ops.empty()) { | 1089 | if (unary->ops.empty()) { |
1081 | Value_t* value = static_cast<Value_t*>(unary->expos.back()); | 1090 | Value_t* value = static_cast<Value_t*>(unary->expos.back()); |
1082 | if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { | 1091 | if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { |
1083 | if (auto exp = chain->get_by_path<Callable_t, Parens_t, Exp_t>()) { | 1092 | if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && parens->extra) { |
1084 | if (auto insideValue = singleValueFrom(exp)) { | 1093 | if (auto insideValue = singleValueFrom(parens->expr)) { |
1085 | return insideValue; | 1094 | return insideValue; |
1086 | } | 1095 | } |
1087 | } | 1096 | } |
@@ -1249,7 +1258,7 @@ private: | |||
1249 | 1258 | ||
1250 | template <class T> | 1259 | template <class T> |
1251 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { | 1260 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { |
1252 | auto res = _parser.parse<T>(std::string(codes)); | 1261 | auto res = _parser.parse<T>(std::string(codes), false); |
1253 | if (res.error) { | 1262 | if (res.error) { |
1254 | throw CompileError(res.error.value().msg, parent); | 1263 | throw CompileError(res.error.value().msg, parent); |
1255 | } | 1264 | } |
@@ -1272,6 +1281,8 @@ private: | |||
1272 | Common, | 1281 | Common, |
1273 | EndWithColon, | 1282 | EndWithColon, |
1274 | EndWithEOP, | 1283 | EndWithEOP, |
1284 | EndWithSlice, | ||
1285 | HasRIndex, | ||
1275 | HasEOP, | 1286 | HasEOP, |
1276 | HasKeyword, | 1287 | HasKeyword, |
1277 | HasUnicode, | 1288 | HasUnicode, |
@@ -1290,6 +1301,9 @@ private: | |||
1290 | if (ast_is<ExistentialOp_t>(chainValue->items.back())) { | 1301 | if (ast_is<ExistentialOp_t>(chainValue->items.back())) { |
1291 | return ChainType::EndWithEOP; | 1302 | return ChainType::EndWithEOP; |
1292 | } | 1303 | } |
1304 | if (ast_is<Slice_t>(chainValue->items.back())) { | ||
1305 | return ChainType::EndWithSlice; | ||
1306 | } | ||
1293 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { | 1307 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { |
1294 | if (dot->name.is<Metatable_t>()) { | 1308 | if (dot->name.is<Metatable_t>()) { |
1295 | return ChainType::Metatable; | 1309 | return ChainType::Metatable; |
@@ -1315,6 +1329,8 @@ private: | |||
1315 | } | 1329 | } |
1316 | } else if (ast_is<ExistentialOp_t>(item)) { | 1330 | } else if (ast_is<ExistentialOp_t>(item)) { |
1317 | return ChainType::HasEOP; | 1331 | return ChainType::HasEOP; |
1332 | } else if (ast_is<ReversedIndex_t>(item)) { | ||
1333 | return ChainType::HasRIndex; | ||
1318 | } | 1334 | } |
1319 | } | 1335 | } |
1320 | return type; | 1336 | return type; |
@@ -1837,6 +1853,7 @@ private: | |||
1837 | case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; | 1853 | case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; |
1838 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; | 1854 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; |
1839 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; | 1855 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; |
1856 | case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break; | ||
1840 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; | 1857 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; |
1841 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; | 1858 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; |
1842 | case id<Comprehension_t>(): { | 1859 | case id<Comprehension_t>(): { |
@@ -2048,13 +2065,16 @@ private: | |||
2048 | if (item.targetVar.empty()) { | 2065 | if (item.targetVar.empty()) { |
2049 | throw CompileError("can only declare variable as const"sv, item.target); | 2066 | throw CompileError("can only declare variable as const"sv, item.target); |
2050 | } | 2067 | } |
2051 | markVarConst(item.targetVar); | 2068 | markVarLocalConst(item.targetVar); |
2052 | } | 2069 | } |
2053 | } | 2070 | } |
2054 | } | 2071 | } |
2055 | } | 2072 | } |
2056 | 2073 | ||
2057 | bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { | 2074 | bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { |
2075 | if (assignment->action.is<SubBackcall_t>()) { | ||
2076 | YUEE("AST node mismatch", assignment->action); | ||
2077 | } | ||
2058 | checkAssignable(assignment->expList); | 2078 | checkAssignable(assignment->expList); |
2059 | BLOCK_START | 2079 | BLOCK_START |
2060 | auto assign = ast_cast<Assign_t>(assignment->action); | 2080 | auto assign = ast_cast<Assign_t>(assignment->action); |
@@ -2317,6 +2337,17 @@ private: | |||
2317 | out.back().insert(0, preDefine); | 2337 | out.back().insert(0, preDefine); |
2318 | return false; | 2338 | return false; |
2319 | } | 2339 | } |
2340 | case id<Try_t>(): { | ||
2341 | auto tryNode = static_cast<Try_t*>(value); | ||
2342 | if (tryNode->eop) { | ||
2343 | auto assignList = assignment->expList.get(); | ||
2344 | std::string preDefine = getPreDefineLine(assignment); | ||
2345 | transformTry(tryNode, out, ExpUsage::Assignment, assignList); | ||
2346 | out.back().insert(0, preDefine); | ||
2347 | return false; | ||
2348 | } | ||
2349 | break; | ||
2350 | } | ||
2320 | case id<Switch_t>(): { | 2351 | case id<Switch_t>(): { |
2321 | auto switchNode = static_cast<Switch_t*>(value); | 2352 | auto switchNode = static_cast<Switch_t*>(value); |
2322 | auto assignList = assignment->expList.get(); | 2353 | auto assignList = assignment->expList.get(); |
@@ -2388,6 +2419,13 @@ private: | |||
2388 | out.back().insert(0, preDefine); | 2419 | out.back().insert(0, preDefine); |
2389 | return false; | 2420 | return false; |
2390 | } | 2421 | } |
2422 | case id<Repeat_t>(): { | ||
2423 | auto expList = assignment->expList.get(); | ||
2424 | std::string preDefine = getPreDefineLine(assignment); | ||
2425 | transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList); | ||
2426 | out.back().insert(0, preDefine); | ||
2427 | return false; | ||
2428 | } | ||
2391 | case id<TableLit_t>(): { | 2429 | case id<TableLit_t>(): { |
2392 | auto tableLit = static_cast<TableLit_t*>(value); | 2430 | auto tableLit = static_cast<TableLit_t*>(value); |
2393 | if (hasSpreadExp(tableLit->values.objects())) { | 2431 | if (hasSpreadExp(tableLit->values.objects())) { |
@@ -2440,12 +2478,14 @@ private: | |||
2440 | switch (type) { | 2478 | switch (type) { |
2441 | case ChainType::HasEOP: | 2479 | case ChainType::HasEOP: |
2442 | case ChainType::EndWithColon: | 2480 | case ChainType::EndWithColon: |
2481 | case ChainType::EndWithSlice: | ||
2443 | case ChainType::MetaFieldInvocation: { | 2482 | case ChainType::MetaFieldInvocation: { |
2444 | std::string preDefine = getPreDefineLine(assignment); | 2483 | std::string preDefine = getPreDefineLine(assignment); |
2445 | transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); | 2484 | transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); |
2446 | out.back().insert(0, preDefine); | 2485 | out.back().insert(0, preDefine); |
2447 | return false; | 2486 | return false; |
2448 | } | 2487 | } |
2488 | case ChainType::HasRIndex: | ||
2449 | case ChainType::HasKeyword: | 2489 | case ChainType::HasKeyword: |
2450 | case ChainType::HasUnicode: | 2490 | case ChainType::HasUnicode: |
2451 | case ChainType::Macro: | 2491 | case ChainType::Macro: |
@@ -2461,6 +2501,10 @@ private: | |||
2461 | auto info = extractDestructureInfo(assignment, false, optionalDestruct); | 2501 | auto info = extractDestructureInfo(assignment, false, optionalDestruct); |
2462 | if (info.destructures.empty()) { | 2502 | if (info.destructures.empty()) { |
2463 | transformAssignmentCommon(assignment, out); | 2503 | transformAssignmentCommon(assignment, out); |
2504 | if (assignment->expList->followStmt) { | ||
2505 | transformStatement(assignment->expList->followStmt, out); | ||
2506 | assignment->expList->followStmtProcessed = true; | ||
2507 | } | ||
2464 | return true; | 2508 | return true; |
2465 | } else { | 2509 | } else { |
2466 | auto x = assignment; | 2510 | auto x = assignment; |
@@ -2726,8 +2770,12 @@ private: | |||
2726 | temp.push_back(indent() + "end"s + nlr(x)); | 2770 | temp.push_back(indent() + "end"s + nlr(x)); |
2727 | } | 2771 | } |
2728 | out.push_back(join(temp)); | 2772 | out.push_back(join(temp)); |
2773 | if (assignment->expList->followStmt) { | ||
2774 | transformStatement(assignment->expList->followStmt, out); | ||
2775 | assignment->expList->followStmtProcessed = true; | ||
2776 | } | ||
2777 | return false; | ||
2729 | } | 2778 | } |
2730 | return false; | ||
2731 | } | 2779 | } |
2732 | 2780 | ||
2733 | void transformAssignItem(ast_node* value, str_list& out) { | 2781 | void transformAssignItem(ast_node* value, str_list& out) { |
@@ -2793,20 +2841,46 @@ private: | |||
2793 | if (!tableItems) throw CompileError("invalid destructure value"sv, node); | 2841 | if (!tableItems) throw CompileError("invalid destructure value"sv, node); |
2794 | std::list<DestructItem> pairs; | 2842 | std::list<DestructItem> pairs; |
2795 | int index = 0; | 2843 | int index = 0; |
2844 | int count = 0; | ||
2845 | bool hasSpread = false; | ||
2796 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); | 2846 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); |
2797 | for (auto pair : *tableItems) { | 2847 | for (auto pair : *tableItems) { |
2798 | switch (pair->get_id()) { | 2848 | switch (pair->get_id()) { |
2799 | case id<Exp_t>(): | 2849 | case id<Exp_t>(): |
2800 | case id<NormalDef_t>(): { | 2850 | case id<NormalDef_t>(): { |
2851 | ++index; | ||
2801 | Exp_t* defVal = nullptr; | 2852 | Exp_t* defVal = nullptr; |
2802 | if (auto nd = ast_cast<NormalDef_t>(pair)) { | 2853 | if (auto nd = ast_cast<NormalDef_t>(pair)) { |
2803 | pair = nd->item.get(); | 2854 | pair = nd->item.get(); |
2804 | defVal = nd->defVal.get(); | 2855 | defVal = nd->defVal.get(); |
2805 | } | 2856 | } |
2806 | ++index; | 2857 | bool assignable = false; |
2807 | if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) { | 2858 | try { |
2859 | assignable = isAssignable(static_cast<Exp_t*>(pair)); | ||
2860 | } catch (const CompileError& e) { | ||
2861 | if (!varDefOnly) throw e; | ||
2862 | } | ||
2863 | if (!assignable && !varDefOnly) { | ||
2864 | if (optional) break; | ||
2808 | throw CompileError("can't destructure value"sv, pair); | 2865 | throw CompileError("can't destructure value"sv, pair); |
2809 | } | 2866 | } |
2867 | ast_ptr<true, ast_node> indexItem; | ||
2868 | if (hasSpread) { | ||
2869 | int rIndex = count - index; | ||
2870 | indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair)); | ||
2871 | } else { | ||
2872 | indexItem.set(toAst<Exp_t>(std::to_string(index), pair)); | ||
2873 | } | ||
2874 | if (optional && varDefOnly && !assignable) { | ||
2875 | if (defVal) { | ||
2876 | throw CompileError("default value is not supported here"sv, defVal); | ||
2877 | } | ||
2878 | auto exp = static_cast<Exp_t*>(pair); | ||
2879 | auto chain = exp->new_ptr<ChainValue_t>(); | ||
2880 | chain->items.push_back(indexItem); | ||
2881 | pairs.push_back({exp, Empty, chain, nullptr}); | ||
2882 | break; | ||
2883 | } | ||
2810 | auto value = singleValueFrom(pair); | 2884 | auto value = singleValueFrom(pair); |
2811 | auto item = value->item.get(); | 2885 | auto item = value->item.get(); |
2812 | ast_node* subExp = ast_cast<SimpleTable_t>(item); | 2886 | ast_node* subExp = ast_cast<SimpleTable_t>(item); |
@@ -2817,7 +2891,6 @@ private: | |||
2817 | throw CompileError("default value is not supported here"sv, defVal); | 2891 | throw CompileError("default value is not supported here"sv, defVal); |
2818 | } | 2892 | } |
2819 | } | 2893 | } |
2820 | auto indexItem = toAst<Exp_t>(std::to_string(index), value); | ||
2821 | for (auto& p : subPairs) { | 2894 | for (auto& p : subPairs) { |
2822 | if (sep) p.structure->items.push_front(sep); | 2895 | if (sep) p.structure->items.push_front(sep); |
2823 | p.structure->items.push_front(indexItem); | 2896 | p.structure->items.push_front(indexItem); |
@@ -2828,7 +2901,6 @@ private: | |||
2828 | auto varName = singleVariableFrom(exp, AccessType::None); | 2901 | auto varName = singleVariableFrom(exp, AccessType::None); |
2829 | if (varName == "_"sv) break; | 2902 | if (varName == "_"sv) break; |
2830 | auto chain = exp->new_ptr<ChainValue_t>(); | 2903 | auto chain = exp->new_ptr<ChainValue_t>(); |
2831 | auto indexItem = toAst<Exp_t>(std::to_string(index), exp); | ||
2832 | chain->items.push_back(indexItem); | 2904 | chain->items.push_back(indexItem); |
2833 | pairs.push_back({exp, | 2905 | pairs.push_back({exp, |
2834 | varName, | 2906 | varName, |
@@ -2886,7 +2958,25 @@ private: | |||
2886 | } | 2958 | } |
2887 | } | 2959 | } |
2888 | if (auto exp = np->value.as<Exp_t>()) { | 2960 | if (auto exp = np->value.as<Exp_t>()) { |
2889 | if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); | 2961 | bool assignable = false; |
2962 | try { | ||
2963 | assignable = isAssignable(exp); | ||
2964 | } catch (const CompileError& e) { | ||
2965 | if (!varDefOnly) throw e; | ||
2966 | } | ||
2967 | if (!assignable && !varDefOnly) { | ||
2968 | if (optional) break; | ||
2969 | throw CompileError("can't destructure value"sv, pair); | ||
2970 | } | ||
2971 | if (optional && varDefOnly && !assignable) { | ||
2972 | if (defVal) { | ||
2973 | throw CompileError("default value is not supported here"sv, defVal); | ||
2974 | } | ||
2975 | auto chain = exp->new_ptr<ChainValue_t>(); | ||
2976 | if (keyIndex) chain->items.push_back(keyIndex); | ||
2977 | pairs.push_back({exp, Empty, chain, nullptr}); | ||
2978 | break; | ||
2979 | } | ||
2890 | auto item = singleValueFrom(exp)->item.get(); | 2980 | auto item = singleValueFrom(exp)->item.get(); |
2891 | ast_node* subExp = ast_cast<SimpleTable_t>(item); | 2981 | ast_node* subExp = ast_cast<SimpleTable_t>(item); |
2892 | if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { | 2982 | if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { |
@@ -2935,7 +3025,13 @@ private: | |||
2935 | auto tb = static_cast<TableBlockIndent_t*>(pair); | 3025 | auto tb = static_cast<TableBlockIndent_t*>(pair); |
2936 | ++index; | 3026 | ++index; |
2937 | auto subPairs = destructFromExp(tb, varDefOnly, optional); | 3027 | auto subPairs = destructFromExp(tb, varDefOnly, optional); |
2938 | auto indexItem = toAst<Exp_t>(std::to_string(index), tb); | 3028 | ast_ptr<true, ast_node> indexItem; |
3029 | if (hasSpread) { | ||
3030 | int rIndex = count - index; | ||
3031 | indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb)); | ||
3032 | } else { | ||
3033 | indexItem.set(toAst<Exp_t>(std::to_string(index), tb)); | ||
3034 | } | ||
2939 | for (auto& p : subPairs) { | 3035 | for (auto& p : subPairs) { |
2940 | if (sep) p.structure->items.push_front(sep); | 3036 | if (sep) p.structure->items.push_front(sep); |
2941 | p.structure->items.push_front(indexItem); | 3037 | p.structure->items.push_front(indexItem); |
@@ -2992,6 +3088,42 @@ private: | |||
2992 | subMetaDestruct->values.push_back(newPairDef); | 3088 | subMetaDestruct->values.push_back(newPairDef); |
2993 | break; | 3089 | break; |
2994 | } | 3090 | } |
3091 | case id<SpreadListExp_t>(): | ||
3092 | case id<SpreadExp_t>(): { | ||
3093 | ++index; | ||
3094 | if (hasSpread) { | ||
3095 | throw CompileError("duplicated spread expression"sv, pair); | ||
3096 | } | ||
3097 | hasSpread = true; | ||
3098 | for (auto item : *tableItems) { | ||
3099 | if (ast_is< | ||
3100 | SpreadListExp_t, SpreadExp_t, | ||
3101 | TableBlockIndent_t, | ||
3102 | Exp_t, NormalDef_t>(item)) { | ||
3103 | count++; | ||
3104 | } | ||
3105 | } | ||
3106 | Exp_t* exp = nullptr; | ||
3107 | if (auto se = ast_cast<SpreadExp_t>(pair)) { | ||
3108 | exp = se->exp.get(); | ||
3109 | } else { | ||
3110 | exp = ast_to<SpreadListExp_t>(pair)->exp.get(); | ||
3111 | } | ||
3112 | auto varName = singleVariableFrom(exp, AccessType::None); | ||
3113 | if (varName == "_"sv) break; | ||
3114 | int start = index; | ||
3115 | int stop = index - count - 1; | ||
3116 | auto chain = exp->new_ptr<ChainValue_t>(); | ||
3117 | auto slice = toAst<Slice_t>( | ||
3118 | '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp); | ||
3119 | chain->items.push_back(slice); | ||
3120 | auto nil = toAst<Exp_t>("nil"sv, slice); | ||
3121 | pairs.push_back({exp, | ||
3122 | varName, | ||
3123 | chain, | ||
3124 | nil.get()}); | ||
3125 | break; | ||
3126 | } | ||
2995 | default: YUEE("AST node mismatch", pair); break; | 3127 | default: YUEE("AST node mismatch", pair); break; |
2996 | } | 3128 | } |
2997 | } | 3129 | } |
@@ -3108,7 +3240,11 @@ private: | |||
3108 | break; | 3240 | break; |
3109 | default: YUEE("AST node mismatch", destructNode); break; | 3241 | default: YUEE("AST node mismatch", destructNode); break; |
3110 | } | 3242 | } |
3111 | if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); | 3243 | if (dlist->empty()) { |
3244 | if (!optional) { | ||
3245 | throw CompileError("expect items to be destructured"sv, destructNode); | ||
3246 | } | ||
3247 | } | ||
3112 | for (auto item : *dlist) { | 3248 | for (auto item : *dlist) { |
3113 | switch (item->get_id()) { | 3249 | switch (item->get_id()) { |
3114 | case id<MetaVariablePairDef_t>(): { | 3250 | case id<MetaVariablePairDef_t>(): { |
@@ -3244,7 +3380,9 @@ private: | |||
3244 | simpleValue->value.set(tab); | 3380 | simpleValue->value.set(tab); |
3245 | auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); | 3381 | auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); |
3246 | if (pairs.empty()) { | 3382 | if (pairs.empty()) { |
3247 | throw CompileError("expect items to be destructured"sv, tab); | 3383 | if (!optional) { |
3384 | throw CompileError("expect items to be destructured"sv, tab); | ||
3385 | } | ||
3248 | } | 3386 | } |
3249 | destruct.items = std::move(pairs); | 3387 | destruct.items = std::move(pairs); |
3250 | if (!varDefOnly) { | 3388 | if (!varDefOnly) { |
@@ -3262,6 +3400,7 @@ private: | |||
3262 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { | 3400 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { |
3263 | auto p = destruct.value.get(); | 3401 | auto p = destruct.value.get(); |
3264 | auto parens = p->new_ptr<Parens_t>(); | 3402 | auto parens = p->new_ptr<Parens_t>(); |
3403 | parens->extra = true; | ||
3265 | if (auto tableBlock = ast_cast<TableBlock_t>(p)) { | 3404 | if (auto tableBlock = ast_cast<TableBlock_t>(p)) { |
3266 | auto tableLit = p->new_ptr<TableLit_t>(); | 3405 | auto tableLit = p->new_ptr<TableLit_t>(); |
3267 | tableLit->values.dup(tableBlock->values); | 3406 | tableLit->values.dup(tableBlock->values); |
@@ -3282,7 +3421,7 @@ private: | |||
3282 | destruct.valueVar.clear(); | 3421 | destruct.valueVar.clear(); |
3283 | } | 3422 | } |
3284 | } | 3423 | } |
3285 | destructs.push_back(destruct); | 3424 | destructs.push_back(std::move(destruct)); |
3286 | } | 3425 | } |
3287 | } | 3426 | } |
3288 | } else { | 3427 | } else { |
@@ -4201,12 +4340,22 @@ private: | |||
4201 | 4340 | ||
4202 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { | 4341 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { |
4203 | if (checkUpValueFuncAvailable(exp)) { | 4342 | if (checkUpValueFuncAvailable(exp)) { |
4343 | auto block = exp->new_ptr<Block_t>(); | ||
4344 | if (auto sVal = simpleSingleValueFrom(exp)) { | ||
4345 | if (auto doNode = sVal->value.as<Do_t>()) { | ||
4346 | if (auto blk = doNode->body->content.as<Block_t>()) { | ||
4347 | block->statements.dup(blk->statements); | ||
4348 | } else { | ||
4349 | block->statements.push_back(doNode->body->content.to<Statement_t>()); | ||
4350 | } | ||
4351 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); | ||
4352 | } | ||
4353 | } | ||
4204 | auto returnNode = exp->new_ptr<Return_t>(); | 4354 | auto returnNode = exp->new_ptr<Return_t>(); |
4205 | returnNode->explicitReturn = false; | 4355 | returnNode->explicitReturn = false; |
4206 | auto returnList = exp->new_ptr<ExpListLow_t>(); | 4356 | auto returnList = exp->new_ptr<ExpListLow_t>(); |
4207 | returnList->exprs.push_back(exp); | 4357 | returnList->exprs.push_back(exp); |
4208 | returnNode->valueList.set(returnList); | 4358 | returnNode->valueList.set(returnList); |
4209 | auto block = exp->new_ptr<Block_t>(); | ||
4210 | auto stmt = exp->new_ptr<Statement_t>(); | 4359 | auto stmt = exp->new_ptr<Statement_t>(); |
4211 | stmt->content.set(returnNode); | 4360 | stmt->content.set(returnNode); |
4212 | block->statements.push_back(stmt); | 4361 | block->statements.push_back(stmt); |
@@ -4283,7 +4432,9 @@ private: | |||
4283 | return false; | 4432 | return false; |
4284 | }; | 4433 | }; |
4285 | switch (usage) { | 4434 | switch (usage) { |
4286 | case ExpUsage::Common: YUEE("AST node mismatch", x); return; | 4435 | case ExpUsage::Common: |
4436 | YUEE("AST node mismatch", x); | ||
4437 | return; | ||
4287 | case ExpUsage::Return: | 4438 | case ExpUsage::Return: |
4288 | case ExpUsage::Closure: { | 4439 | case ExpUsage::Closure: { |
4289 | prepareValue(); | 4440 | prepareValue(); |
@@ -4406,6 +4557,7 @@ private: | |||
4406 | case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; | 4557 | case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; |
4407 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; | 4558 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; |
4408 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; | 4559 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; |
4560 | case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break; | ||
4409 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; | 4561 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; |
4410 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; | 4562 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; |
4411 | case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; | 4563 | case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; |
@@ -4725,11 +4877,7 @@ private: | |||
4725 | auto newBody = x->new_ptr<Body_t>(); | 4877 | auto newBody = x->new_ptr<Body_t>(); |
4726 | newBody->content.set(followingBlock); | 4878 | newBody->content.set(followingBlock); |
4727 | { | 4879 | { |
4728 | auto doNode = x->new_ptr<Do_t>(); | 4880 | if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) { |
4729 | doNode->body.set(newBody); | ||
4730 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
4731 | simpleValue->value.set(doNode); | ||
4732 | if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) { | ||
4733 | auto [funcName, args] = std::move(*result); | 4881 | auto [funcName, args] = std::move(*result); |
4734 | str_list finalArgs; | 4882 | str_list finalArgs; |
4735 | for (const auto& arg : args) { | 4883 | for (const auto& arg : args) { |
@@ -4737,9 +4885,13 @@ private: | |||
4737 | finalArgs.push_back(arg); | 4885 | finalArgs.push_back(arg); |
4738 | } | 4886 | } |
4739 | } | 4887 | } |
4740 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); | 4888 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x)); |
4741 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); | 4889 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); |
4742 | ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); | 4890 | auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back()); |
4891 | if (finalArgs.empty()) { | ||
4892 | invokArgs->args.clear(); | ||
4893 | } | ||
4894 | invokArgs->args.dup(newInvoke->args); | ||
4743 | transformBlock(newBlock, out, usage, assignList, isRoot); | 4895 | transformBlock(newBlock, out, usage, assignList, isRoot); |
4744 | return; | 4896 | return; |
4745 | } | 4897 | } |
@@ -4750,6 +4902,7 @@ private: | |||
4750 | newSimpleValue->value.set(funLit); | 4902 | newSimpleValue->value.set(funLit); |
4751 | auto newExpInParens = newExp(newSimpleValue, x); | 4903 | auto newExpInParens = newExp(newSimpleValue, x); |
4752 | auto newParens = x->new_ptr<Parens_t>(); | 4904 | auto newParens = x->new_ptr<Parens_t>(); |
4905 | newParens->extra = true; | ||
4753 | newParens->expr.set(newExpInParens); | 4906 | newParens->expr.set(newExpInParens); |
4754 | auto newCallable = x->new_ptr<Callable_t>(); | 4907 | auto newCallable = x->new_ptr<Callable_t>(); |
4755 | newCallable->item.set(newParens); | 4908 | newCallable->item.set(newParens); |
@@ -4795,7 +4948,7 @@ private: | |||
4795 | auto varName = variableToString(ast_to<Variable_t>(var)); | 4948 | auto varName = variableToString(ast_to<Variable_t>(var)); |
4796 | auto closeVar = getUnusedName("_close_"sv); | 4949 | auto closeVar = getUnusedName("_close_"sv); |
4797 | addToScope(closeVar); | 4950 | addToScope(closeVar); |
4798 | getCloses.push_back(closeVar + "=if type("s + varName + ") in ['table', 'userdata'] then assert "s + varName + ".<> and "s + varName +".<close>, \""s + "variable '"s + varName + "' got a non-closable value\" elseif "s + varName + " == nil then nil else error \""s + "variable '"s + varName + "' got a non-closable value\""); | 4951 | getCloses.push_back(closeVar + "=if type("s + varName + ") in ['table', 'userdata'] then assert "s + varName + ".<> and "s + varName + ".<close>, \""s + "variable '"s + varName + "' got a non-closable value\" elseif "s + varName + " == nil then nil else error \""s + "variable '"s + varName + "' got a non-closable value\""); |
4799 | doCloses.push_front(closeVar + "? "s + varName); | 4952 | doCloses.push_front(closeVar + "? "s + varName); |
4800 | } | 4953 | } |
4801 | popScope(); | 4954 | popScope(); |
@@ -4815,6 +4968,38 @@ private: | |||
4815 | newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); | 4968 | newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); |
4816 | transformBlock(newBlock, out, usage, assignList, isRoot); | 4969 | transformBlock(newBlock, out, usage, assignList, isRoot); |
4817 | return; | 4970 | return; |
4971 | } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>(); | ||
4972 | expListAssign && expListAssign->action && expListAssign->action.is<SubBackcall_t>()) { | ||
4973 | auto x = *nodes.begin(); | ||
4974 | auto newBlock = x->new_ptr<Block_t>(); | ||
4975 | if (it != nodes.begin()) { | ||
4976 | for (auto i = nodes.begin(); i != it; ++i) { | ||
4977 | newBlock->statements.push_back(*i); | ||
4978 | } | ||
4979 | } | ||
4980 | auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get()); | ||
4981 | auto backcall = expListAssign->new_ptr<Backcall_t>(); | ||
4982 | auto argsDef = backcall->new_ptr<FnArgsDef_t>(); | ||
4983 | try { | ||
4984 | auto defList = toAst<FnArgDefList_t>(YueFormat{}.toString(expListAssign->expList), expListAssign->expList); | ||
4985 | argsDef->defList.set(defList); | ||
4986 | } catch (const std::exception&) { | ||
4987 | throw CompileError("backcall syntax error", backcall); | ||
4988 | } | ||
4989 | backcall->argsDef.set(argsDef); | ||
4990 | backcall->arrow.set(doBackcall->arrow); | ||
4991 | backcall->value.set(doBackcall->value); | ||
4992 | auto newStmt = backcall->new_ptr<Statement_t>(); | ||
4993 | newStmt->content.set(backcall); | ||
4994 | newStmt->comments.dup(stmt->comments); | ||
4995 | newStmt->appendix.set(stmt->appendix); | ||
4996 | newBlock->statements.push_back(newStmt); | ||
4997 | auto ait = it; | ||
4998 | for (auto i = ++ait; i != nodes.end(); ++i) { | ||
4999 | newBlock->statements.push_back(*i); | ||
5000 | } | ||
5001 | transformBlock(newBlock, out, usage, assignList, isRoot); | ||
5002 | return; | ||
4818 | } | 5003 | } |
4819 | if (auto local = stmt->content.as<Local_t>()) { | 5004 | if (auto local = stmt->content.as<Local_t>()) { |
4820 | if (!local->collected) { | 5005 | if (!local->collected) { |
@@ -4986,36 +5171,45 @@ private: | |||
4986 | if (!nodes.empty()) { | 5171 | if (!nodes.empty()) { |
4987 | str_list temp; | 5172 | str_list temp; |
4988 | for (auto node : nodes) { | 5173 | for (auto node : nodes) { |
4989 | currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; | 5174 | auto transformNode = [&]() { |
4990 | transformStatement(static_cast<Statement_t*>(node), temp); | 5175 | currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; |
4991 | if (isRoot && !_rootDefs.empty()) { | 5176 | transformStatement(static_cast<Statement_t*>(node), temp); |
4992 | auto last = std::move(temp.back()); | 5177 | if (isRoot && !_rootDefs.empty()) { |
4993 | temp.pop_back(); | 5178 | auto last = std::move(temp.back()); |
4994 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); | 5179 | temp.pop_back(); |
4995 | _rootDefs.clear(); | 5180 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); |
4996 | temp.push_back(std::move(last)); | 5181 | _rootDefs.clear(); |
4997 | } | 5182 | temp.push_back(std::move(last)); |
4998 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { | 5183 | } |
4999 | auto rit = ++temp.rbegin(); | 5184 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { |
5000 | if (rit != temp.rend() && !rit->empty()) { | 5185 | auto rit = ++temp.rbegin(); |
5001 | auto index = std::string::npos; | 5186 | if (rit != temp.rend() && !rit->empty()) { |
5002 | if (_config.reserveLineNumber) { | 5187 | auto index = std::string::npos; |
5003 | index = rit->rfind(" -- "sv); | 5188 | if (_config.reserveLineNumber) { |
5004 | } else { | 5189 | index = rit->rfind(" -- "sv); |
5005 | index = rit->find_last_not_of('\n'); | 5190 | } else { |
5006 | if (index != std::string::npos) index++; | 5191 | index = rit->find_last_not_of('\n'); |
5007 | } | 5192 | if (index != std::string::npos) index++; |
5008 | if (index != std::string::npos) { | ||
5009 | auto ending = rit->substr(0, index); | ||
5010 | auto ind = ending.find_last_of(" \t\n"sv); | ||
5011 | if (ind != std::string::npos) { | ||
5012 | ending = ending.substr(ind + 1); | ||
5013 | } | 5193 | } |
5014 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | 5194 | if (index != std::string::npos) { |
5015 | rit->insert(index, ";"sv); | 5195 | auto ending = rit->substr(0, index); |
5196 | auto ind = ending.find_last_of(" \t\n"sv); | ||
5197 | if (ind != std::string::npos) { | ||
5198 | ending = ending.substr(ind + 1); | ||
5199 | } | ||
5200 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | ||
5201 | rit->insert(index, ";"sv); | ||
5202 | } | ||
5016 | } | 5203 | } |
5017 | } | 5204 | } |
5018 | } | 5205 | } |
5206 | }; | ||
5207 | if (_config.lax) { | ||
5208 | try { | ||
5209 | transformNode(); | ||
5210 | } catch (const CompileError&) { } | ||
5211 | } else { | ||
5212 | transformNode(); | ||
5019 | } | 5213 | } |
5020 | } | 5214 | } |
5021 | out.push_back(join(temp)); | 5215 | out.push_back(join(temp)); |
@@ -5224,18 +5418,29 @@ private: | |||
5224 | auto macroLit = macro->decl.to<MacroLit_t>(); | 5418 | auto macroLit = macro->decl.to<MacroLit_t>(); |
5225 | auto argsDef = macroLit->argsDef.get(); | 5419 | auto argsDef = macroLit->argsDef.get(); |
5226 | str_list newArgs; | 5420 | str_list newArgs; |
5421 | str_list argChecks; | ||
5422 | bool hasCheck = false; | ||
5227 | if (argsDef) { | 5423 | if (argsDef) { |
5228 | for (auto def_ : argsDef->definitions.objects()) { | 5424 | for (auto def_ : argsDef->definitions.objects()) { |
5229 | auto def = static_cast<FnArgDef_t*>(def_); | 5425 | auto def = static_cast<FnArgDef_t*>(def_); |
5230 | if (def->name.is<SelfItem_t>()) { | 5426 | if (def->name.is<SelfItem_t>()) { |
5231 | throw CompileError("self name is not supported for macro function argument"sv, def->name); | 5427 | throw CompileError("self name is not supported for macro function argument"sv, def->name); |
5232 | } else { | 5428 | } else { |
5429 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
5430 | if (def->label) { | ||
5431 | hasCheck = true; | ||
5432 | const auto& astName = argChecks.emplace_back(_parser.toString(def->label)); | ||
5433 | if (!_parser.hasAST(astName)) { | ||
5434 | throw CompileError("invalid AST name"sv, def->label); | ||
5435 | } | ||
5436 | } else { | ||
5437 | argChecks.emplace_back(); | ||
5438 | } | ||
5233 | std::string defVal; | 5439 | std::string defVal; |
5234 | if (def->defaultValue) { | 5440 | if (def->defaultValue) { |
5235 | defVal = _parser.toString(def->defaultValue); | 5441 | defVal = _parser.toString(def->defaultValue); |
5236 | Utils::trim(defVal); | 5442 | Utils::trim(defVal); |
5237 | defVal.insert(0, "=[==========["sv); | 5443 | defVal = '=' + Utils::toLuaDoubleString(defVal); |
5238 | defVal.append("]==========]"sv); | ||
5239 | } | 5444 | } |
5240 | newArgs.emplace_back(_parser.toString(def->name) + defVal); | 5445 | newArgs.emplace_back(_parser.toString(def->name) + defVal); |
5241 | } | 5446 | } |
@@ -5243,6 +5448,14 @@ private: | |||
5243 | if (argsDef->varArg) { | 5448 | if (argsDef->varArg) { |
5244 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); | 5449 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); |
5245 | } | 5450 | } |
5451 | if (argsDef->label) { | ||
5452 | hasCheck = true; | ||
5453 | const auto& astName = _parser.toString(argsDef->label); | ||
5454 | if (!_parser.hasAST(astName)) { | ||
5455 | throw CompileError("invalid AST name"sv, argsDef->label); | ||
5456 | } | ||
5457 | argChecks.emplace_back("..."s + astName); | ||
5458 | } | ||
5246 | } | 5459 | } |
5247 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); | 5460 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); |
5248 | auto chunkName = "=(macro "s + macroName + ')'; | 5461 | auto chunkName = "=(macro "s + macroName + ')'; |
@@ -5273,6 +5486,24 @@ private: | |||
5273 | throw CompileError("failed to generate macro function\n"s + err, macroLit); | 5486 | throw CompileError("failed to generate macro function\n"s + err, macroLit); |
5274 | } // cur true macro | 5487 | } // cur true macro |
5275 | lua_remove(L, -2); // cur macro | 5488 | lua_remove(L, -2); // cur macro |
5489 | if (hasCheck) { | ||
5490 | lua_createtable(L, 0, 0); // cur macro checks | ||
5491 | int i = 1; | ||
5492 | for (const auto& check : argChecks) { | ||
5493 | if (check.empty()) { | ||
5494 | lua_pushboolean(L, 0); | ||
5495 | lua_rawseti(L, -2, i); | ||
5496 | } else { | ||
5497 | lua_pushlstring(L, check.c_str(), check.size()); | ||
5498 | lua_rawseti(L, -2, i); | ||
5499 | } | ||
5500 | i++; | ||
5501 | } | ||
5502 | lua_createtable(L, 2, 0); // cur macro checks macrotab | ||
5503 | lua_insert(L, -3); // cur macrotab macro checks | ||
5504 | lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro | ||
5505 | lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab | ||
5506 | } // cur macro | ||
5276 | if (exporting && _config.exporting && !_config.module.empty()) { | 5507 | if (exporting && _config.exporting && !_config.module.empty()) { |
5277 | pushModuleTable(_config.module); // cur macro module | 5508 | pushModuleTable(_config.module); // cur macro module |
5278 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name | 5509 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name |
@@ -5347,6 +5578,9 @@ private: | |||
5347 | case id<While_t>(): | 5578 | case id<While_t>(): |
5348 | transformWhileInPlace(static_cast<While_t*>(value), out); | 5579 | transformWhileInPlace(static_cast<While_t*>(value), out); |
5349 | return; | 5580 | return; |
5581 | case id<Repeat_t>(): | ||
5582 | transformRepeatInPlace(static_cast<Repeat_t*>(value), out); | ||
5583 | return; | ||
5350 | case id<For_t>(): | 5584 | case id<For_t>(): |
5351 | transformForInPlace(static_cast<For_t*>(value), out); | 5585 | transformForInPlace(static_cast<For_t*>(value), out); |
5352 | return; | 5586 | return; |
@@ -5427,7 +5661,11 @@ private: | |||
5427 | auto def = static_cast<FnArgDef_t*>(_def); | 5661 | auto def = static_cast<FnArgDef_t*>(_def); |
5428 | auto& arg = argItems.emplace_back(); | 5662 | auto& arg = argItems.emplace_back(); |
5429 | switch (def->name->get_id()) { | 5663 | switch (def->name->get_id()) { |
5430 | case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; | 5664 | case id<Variable_t>(): { |
5665 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
5666 | arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); | ||
5667 | break; | ||
5668 | } | ||
5431 | case id<SelfItem_t>(): { | 5669 | case id<SelfItem_t>(): { |
5432 | assignSelf = true; | 5670 | assignSelf = true; |
5433 | if (def->op) { | 5671 | if (def->op) { |
@@ -5566,10 +5804,50 @@ private: | |||
5566 | } | 5804 | } |
5567 | } | 5805 | } |
5568 | 5806 | ||
5807 | bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | ||
5808 | auto x = chainList.front(); | ||
5809 | if (ast_is<Slice_t>(chainList.back())) { | ||
5810 | auto comp = x->new_ptr<Comprehension_t>(); | ||
5811 | { | ||
5812 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
5813 | for (auto item : chainList) { | ||
5814 | chainValue->items.push_back(item); | ||
5815 | } | ||
5816 | auto itemVar = getUnusedName("_item_"sv); | ||
5817 | auto expCode = YueFormat{}.toString(chainValue); | ||
5818 | auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']'; | ||
5819 | comp.set(toAst<Comprehension_t>(compCode, x)); | ||
5820 | } | ||
5821 | switch (usage) { | ||
5822 | case ExpUsage::Assignment: { | ||
5823 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
5824 | simpleValue->value.set(comp); | ||
5825 | auto exp = newExp(simpleValue, x); | ||
5826 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
5827 | assignment->expList.set(assignList); | ||
5828 | auto assign = x->new_ptr<Assign_t>(); | ||
5829 | assign->values.push_back(exp); | ||
5830 | assignment->action.set(assign); | ||
5831 | transformAssignment(assignment, out); | ||
5832 | break; | ||
5833 | } | ||
5834 | case ExpUsage::Return: | ||
5835 | transformComprehension(comp, out, ExpUsage::Return); | ||
5836 | break; | ||
5837 | default: | ||
5838 | transformComprehension(comp, out, ExpUsage::Closure); | ||
5839 | break; | ||
5840 | } | ||
5841 | return true; | ||
5842 | } | ||
5843 | return false; | ||
5844 | } | ||
5845 | |||
5569 | bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | 5846 | bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { |
5570 | auto x = chainList.front(); | 5847 | auto x = chainList.front(); |
5571 | if (ast_is<ExistentialOp_t>(chainList.back())) { | 5848 | if (ast_is<ExistentialOp_t>(chainList.back())) { |
5572 | auto parens = x->new_ptr<Parens_t>(); | 5849 | auto parens = x->new_ptr<Parens_t>(); |
5850 | parens->extra = true; | ||
5573 | { | 5851 | { |
5574 | auto chainValue = x->new_ptr<ChainValue_t>(); | 5852 | auto chainValue = x->new_ptr<ChainValue_t>(); |
5575 | for (auto item : chainList) { | 5853 | for (auto item : chainList) { |
@@ -6082,7 +6360,7 @@ private: | |||
6082 | case id<ColonChainItem_t>(): | 6360 | case id<ColonChainItem_t>(): |
6083 | case id<Exp_t>(): | 6361 | case id<Exp_t>(): |
6084 | if (_withVars.empty()) { | 6362 | if (_withVars.empty()) { |
6085 | throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); | 6363 | throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x); |
6086 | } else { | 6364 | } else { |
6087 | temp.push_back(_withVars.top()); | 6365 | temp.push_back(_withVars.top()); |
6088 | } | 6366 | } |
@@ -6163,6 +6441,7 @@ private: | |||
6163 | ++next; | 6441 | ++next; |
6164 | if (next != chainList.end()) { | 6442 | if (next != chainList.end()) { |
6165 | auto paren = x->new_ptr<Parens_t>(); | 6443 | auto paren = x->new_ptr<Parens_t>(); |
6444 | paren->extra = true; | ||
6166 | paren->expr.set(newExp(chainValue, x)); | 6445 | paren->expr.set(newExp(chainValue, x)); |
6167 | auto ncallable = x->new_ptr<Callable_t>(); | 6446 | auto ncallable = x->new_ptr<Callable_t>(); |
6168 | ncallable->item.set(paren); | 6447 | ncallable->item.set(paren); |
@@ -6215,6 +6494,7 @@ private: | |||
6215 | simpleValue->value.set(funLit); | 6494 | simpleValue->value.set(funLit); |
6216 | auto exp = newExp(simpleValue, x); | 6495 | auto exp = newExp(simpleValue, x); |
6217 | auto paren = x->new_ptr<Parens_t>(); | 6496 | auto paren = x->new_ptr<Parens_t>(); |
6497 | paren->extra = true; | ||
6218 | paren->expr.set(exp); | 6498 | paren->expr.set(exp); |
6219 | auto callable = x->new_ptr<Callable_t>(); | 6499 | auto callable = x->new_ptr<Callable_t>(); |
6220 | callable->item.set(paren); | 6500 | callable->item.set(paren); |
@@ -6226,6 +6506,93 @@ private: | |||
6226 | } | 6506 | } |
6227 | return; | 6507 | return; |
6228 | } | 6508 | } |
6509 | break; | ||
6510 | } | ||
6511 | case id<ReversedIndex_t>(): { | ||
6512 | auto rIndex = static_cast<ReversedIndex_t*>(*it); | ||
6513 | auto current = it; | ||
6514 | auto prevChain = x->new_ptr<ChainValue_t>(); | ||
6515 | for (auto i = chainList.begin(); i != current; ++i) { | ||
6516 | prevChain->items.push_back(*i); | ||
6517 | } | ||
6518 | auto var = singleVariableFrom(prevChain, AccessType::None); | ||
6519 | if (!var.empty() && isLocal(var)) { | ||
6520 | auto indexNode = toAst<Exp_t>('#' + var, rIndex); | ||
6521 | if (rIndex->modifier) { | ||
6522 | auto opValue = rIndex->new_ptr<ExpOpValue_t>(); | ||
6523 | opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex)); | ||
6524 | opValue->pipeExprs.dup(rIndex->modifier->pipeExprs); | ||
6525 | indexNode->opValues.push_back(opValue); | ||
6526 | indexNode->opValues.dup(rIndex->modifier->opValues); | ||
6527 | indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed); | ||
6528 | } | ||
6529 | prevChain->items.push_back(indexNode); | ||
6530 | auto next = current; | ||
6531 | ++next; | ||
6532 | for (auto i = next; i != chainList.end(); ++i) { | ||
6533 | prevChain->items.push_back(*i); | ||
6534 | } | ||
6535 | if (usage == ExpUsage::Assignment) { | ||
6536 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
6537 | assignment->expList.set(assignList); | ||
6538 | auto assign = x->new_ptr<Assign_t>(); | ||
6539 | assign->values.push_back(newExp(prevChain, x)); | ||
6540 | assignment->action.set(assign); | ||
6541 | transformAssignment(assignment, out); | ||
6542 | return; | ||
6543 | } | ||
6544 | transformChainValue(prevChain, out, usage, assignList); | ||
6545 | return; | ||
6546 | } else { | ||
6547 | auto itemVar = getUnusedName("_item_"sv); | ||
6548 | auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x); | ||
6549 | auto stmt1 = x->new_ptr<Statement_t>(); | ||
6550 | stmt1->content.set(asmt); | ||
6551 | auto newChain = x->new_ptr<ChainValue_t>(); | ||
6552 | newChain->items.push_back(toAst<Callable_t>(itemVar, x)); | ||
6553 | auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex); | ||
6554 | if (rIndex->modifier) { | ||
6555 | auto opValue = rIndex->new_ptr<ExpOpValue_t>(); | ||
6556 | opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex)); | ||
6557 | opValue->pipeExprs.dup(rIndex->modifier->pipeExprs); | ||
6558 | indexNode->opValues.push_back(opValue); | ||
6559 | indexNode->opValues.dup(rIndex->modifier->opValues); | ||
6560 | indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed); | ||
6561 | } | ||
6562 | newChain->items.push_back(indexNode); | ||
6563 | auto next = current; | ||
6564 | ++next; | ||
6565 | for (auto i = next; i != chainList.end(); ++i) { | ||
6566 | newChain->items.push_back(*i); | ||
6567 | } | ||
6568 | auto expList = x->new_ptr<ExpList_t>(); | ||
6569 | expList->exprs.push_back(newExp(newChain, x)); | ||
6570 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
6571 | expListAssign->expList.set(expList); | ||
6572 | auto stmt2 = x->new_ptr<Statement_t>(); | ||
6573 | stmt2->content.set(expListAssign); | ||
6574 | auto block = x->new_ptr<Block_t>(); | ||
6575 | block->statements.push_back(stmt1); | ||
6576 | block->statements.push_back(stmt2); | ||
6577 | auto body = x->new_ptr<Body_t>(); | ||
6578 | body->content.set(block); | ||
6579 | auto doNode = x->new_ptr<Do_t>(); | ||
6580 | doNode->body.set(body); | ||
6581 | if (usage == ExpUsage::Assignment) { | ||
6582 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
6583 | assignment->expList.set(assignList); | ||
6584 | auto assign = x->new_ptr<Assign_t>(); | ||
6585 | auto sVal = x->new_ptr<SimpleValue_t>(); | ||
6586 | sVal->value.set(doNode); | ||
6587 | assign->values.push_back(newExp(sVal, x)); | ||
6588 | assignment->action.set(assign); | ||
6589 | transformAssignment(assignment, out); | ||
6590 | return; | ||
6591 | } | ||
6592 | transformDo(doNode, out, usage); | ||
6593 | return; | ||
6594 | } | ||
6595 | break; | ||
6229 | } | 6596 | } |
6230 | } | 6597 | } |
6231 | } | 6598 | } |
@@ -6410,7 +6777,7 @@ private: | |||
6410 | } | 6777 | } |
6411 | } | 6778 | } |
6412 | } | 6779 | } |
6413 | int len = lua_objlen(L, -1); | 6780 | int len = static_cast<int>(lua_objlen(L, -1)); |
6414 | lua_pushnil(L); // cur nil | 6781 | lua_pushnil(L); // cur nil |
6415 | for (int i = len; i >= 1; i--) { | 6782 | for (int i = len; i >= 1; i--) { |
6416 | lua_pop(L, 1); // cur | 6783 | lua_pop(L, 1); // cur |
@@ -6422,7 +6789,25 @@ private: | |||
6422 | break; | 6789 | break; |
6423 | } | 6790 | } |
6424 | } | 6791 | } |
6425 | if (!lua_isfunction(L, -1)) { | 6792 | str_list checks; |
6793 | if (lua_istable(L, -1)) { | ||
6794 | lua_rawgeti(L, -1, 1); // cur macrotab checks | ||
6795 | int len = static_cast<int>(lua_objlen(L, -1)); | ||
6796 | for (int i = 1; i <= len; i++) { | ||
6797 | lua_rawgeti(L, -1, i); | ||
6798 | if (lua_toboolean(L, -1) == 0) { | ||
6799 | checks.emplace_back(); | ||
6800 | } else { | ||
6801 | size_t str_len = 0; | ||
6802 | auto str = lua_tolstring(L, -1, &str_len); | ||
6803 | checks.emplace_back(std::string{str, str_len}); | ||
6804 | } | ||
6805 | lua_pop(L, 1); | ||
6806 | } | ||
6807 | lua_pop(L, 1); | ||
6808 | lua_rawgeti(L, -1, 2); // cur macrotab macroFunc | ||
6809 | lua_remove(L, -2); // cur macroFunc | ||
6810 | } else if (!lua_isfunction(L, -1)) { | ||
6426 | auto code = expandBuiltinMacro(macroName, x); | 6811 | auto code = expandBuiltinMacro(macroName, x); |
6427 | if (!code.empty()) return code; | 6812 | if (!code.empty()) return code; |
6428 | if (macroName == "is_ast"sv) { | 6813 | if (macroName == "is_ast"sv) { |
@@ -6467,11 +6852,34 @@ private: | |||
6467 | } // cur macroFunc | 6852 | } // cur macroFunc |
6468 | pushYue("pcall"sv); // cur macroFunc pcall | 6853 | pushYue("pcall"sv); // cur macroFunc pcall |
6469 | lua_insert(L, -2); // cur pcall macroFunc | 6854 | lua_insert(L, -2); // cur pcall macroFunc |
6470 | if (!lua_checkstack(L, argStrs.size())) { | 6855 | if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) { |
6471 | throw CompileError("too much macro params"s, x); | 6856 | throw CompileError("too much macro params"s, x); |
6472 | } | 6857 | } |
6858 | auto checkIt = checks.begin(); | ||
6859 | node_container::const_iterator argIt; | ||
6860 | if (args) { | ||
6861 | argIt = args->begin(); | ||
6862 | } | ||
6473 | for (const auto& arg : argStrs) { | 6863 | for (const auto& arg : argStrs) { |
6864 | if (checkIt != checks.end()) { | ||
6865 | if (checkIt->empty()) { | ||
6866 | ++checkIt; | ||
6867 | } else { | ||
6868 | if ((*checkIt)[0] == '.') { | ||
6869 | auto astName = checkIt->substr(3); | ||
6870 | if (!_parser.match(astName, arg)) { | ||
6871 | throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt); | ||
6872 | } | ||
6873 | } else { | ||
6874 | if (!_parser.match(*checkIt, arg)) { | ||
6875 | throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt); | ||
6876 | } | ||
6877 | ++checkIt; | ||
6878 | } | ||
6879 | } | ||
6880 | } | ||
6474 | lua_pushlstring(L, arg.c_str(), arg.size()); | 6881 | lua_pushlstring(L, arg.c_str(), arg.size()); |
6882 | ++argIt; | ||
6475 | } // cur pcall macroFunc args... | 6883 | } // cur pcall macroFunc args... |
6476 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; | 6884 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; |
6477 | if (!success) { // cur err | 6885 | if (!success) { // cur err |
@@ -6601,14 +7009,14 @@ private: | |||
6601 | } else { | 7009 | } else { |
6602 | if (!codes.empty()) { | 7010 | if (!codes.empty()) { |
6603 | if (isBlock) { | 7011 | if (isBlock) { |
6604 | info = _parser.parse<BlockEnd_t>(codes); | 7012 | info = _parser.parse<BlockEnd_t>(codes, false); |
6605 | if (info.error) { | 7013 | if (info.error) { |
6606 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); | 7014 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); |
6607 | } | 7015 | } |
6608 | } else { | 7016 | } else { |
6609 | info = _parser.parse<Exp_t>(codes); | 7017 | info = _parser.parse<Exp_t>(codes, false); |
6610 | if (!info.node && allowBlockMacroReturn) { | 7018 | if (!info.node && allowBlockMacroReturn) { |
6611 | info = _parser.parse<BlockEnd_t>(codes); | 7019 | info = _parser.parse<BlockEnd_t>(codes, false); |
6612 | if (info.error) { | 7020 | if (info.error) { |
6613 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); | 7021 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); |
6614 | } | 7022 | } |
@@ -6631,6 +7039,7 @@ private: | |||
6631 | exp.set(info.node); | 7039 | exp.set(info.node); |
6632 | if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { | 7040 | if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { |
6633 | auto paren = x->new_ptr<Parens_t>(); | 7041 | auto paren = x->new_ptr<Parens_t>(); |
7042 | paren->extra = true; | ||
6634 | paren->expr.set(exp); | 7043 | paren->expr.set(exp); |
6635 | auto callable = x->new_ptr<Callable_t>(); | 7044 | auto callable = x->new_ptr<Callable_t>(); |
6636 | callable->item.set(paren); | 7045 | callable->item.set(paren); |
@@ -6743,6 +7152,9 @@ private: | |||
6743 | if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { | 7152 | if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { |
6744 | return; | 7153 | return; |
6745 | } | 7154 | } |
7155 | if (transformChainEndWithSlice(chainList, out, usage, assignList)) { | ||
7156 | return; | ||
7157 | } | ||
6746 | transformChainList(chainList, out, usage, assignList); | 7158 | transformChainList(chainList, out, usage, assignList); |
6747 | } | 7159 | } |
6748 | 7160 | ||
@@ -7138,6 +7550,33 @@ private: | |||
7138 | void transformNum(Num_t* num, str_list& out) { | 7550 | void transformNum(Num_t* num, str_list& out) { |
7139 | std::string numStr = _parser.toString(num); | 7551 | std::string numStr = _parser.toString(num); |
7140 | numStr.erase(std::remove(numStr.begin(), numStr.end(), '_'), numStr.end()); | 7552 | numStr.erase(std::remove(numStr.begin(), numStr.end(), '_'), numStr.end()); |
7553 | if (numStr.size() > 2 && numStr[0] == '0') { | ||
7554 | if (numStr[1] == 'b' || numStr[1] == 'B') { | ||
7555 | std::string binaryPart = numStr.substr(2); | ||
7556 | try { | ||
7557 | unsigned long long value = std::stoull(binaryPart, nullptr, 2); | ||
7558 | numStr = std::to_string(value); | ||
7559 | } catch (const std::exception&) { | ||
7560 | throw CompileError("invalid binary literal"sv, num); | ||
7561 | } | ||
7562 | } else if (getLuaTarget(num) < 502) { | ||
7563 | if (numStr[1] == 'x' || numStr[1] == 'X') { | ||
7564 | if (numStr.find_first_of(".-"sv) != std::string::npos) { | ||
7565 | std::stringstream ss(numStr); | ||
7566 | double v; | ||
7567 | ss >> std::hexfloat >> v; | ||
7568 | if (ss.fail() || !std::isfinite(v)) { | ||
7569 | throw CompileError("invalid hex‑float literal"sv, num); | ||
7570 | } | ||
7571 | std::ostringstream outSs; | ||
7572 | outSs << std::setprecision(17) << v; | ||
7573 | numStr = outSs.str(); | ||
7574 | } else { | ||
7575 | numStr.erase(std::remove(numStr.begin(), numStr.end(), '+'), numStr.end()); | ||
7576 | } | ||
7577 | } | ||
7578 | } | ||
7579 | } | ||
7141 | out.push_back(numStr); | 7580 | out.push_back(numStr); |
7142 | } | 7581 | } |
7143 | 7582 | ||
@@ -7823,6 +8262,11 @@ private: | |||
7823 | } | 8262 | } |
7824 | 8263 | ||
7825 | bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { | 8264 | bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { |
8265 | enum class NumState { | ||
8266 | Unknown, | ||
8267 | Positive, | ||
8268 | Negtive | ||
8269 | }; | ||
7826 | auto x = nameList; | 8270 | auto x = nameList; |
7827 | str_list temp; | 8271 | str_list temp; |
7828 | str_list vars; | 8272 | str_list vars; |
@@ -7889,15 +8333,35 @@ private: | |||
7889 | for (auto item : chainList) { | 8333 | for (auto item : chainList) { |
7890 | chain->items.push_back(item); | 8334 | chain->items.push_back(item); |
7891 | } | 8335 | } |
7892 | std::string startValue("1"sv); | 8336 | std::string startValue; |
8337 | NumState startStatus = NumState::Unknown; | ||
7893 | if (auto exp = slice->startValue.as<Exp_t>()) { | 8338 | if (auto exp = slice->startValue.as<Exp_t>()) { |
7894 | transformExp(exp, temp, ExpUsage::Closure); | 8339 | transformExp(exp, temp, ExpUsage::Closure); |
8340 | if (temp.back().at(0) == '-') { | ||
8341 | if (_parser.match<Num_t>(temp.back().substr(1))) { | ||
8342 | startStatus = NumState::Negtive; | ||
8343 | } | ||
8344 | } else { | ||
8345 | if (_parser.match<Num_t>(temp.back())) { | ||
8346 | startStatus = NumState::Positive; | ||
8347 | } | ||
8348 | } | ||
7895 | startValue = std::move(temp.back()); | 8349 | startValue = std::move(temp.back()); |
7896 | temp.pop_back(); | 8350 | temp.pop_back(); |
7897 | } | 8351 | } |
7898 | std::string stopValue; | 8352 | std::string stopValue; |
8353 | NumState stopStatus = NumState::Unknown; | ||
7899 | if (auto exp = slice->stopValue.as<Exp_t>()) { | 8354 | if (auto exp = slice->stopValue.as<Exp_t>()) { |
7900 | transformExp(exp, temp, ExpUsage::Closure); | 8355 | transformExp(exp, temp, ExpUsage::Closure); |
8356 | if (temp.back().at(0) == '-') { | ||
8357 | if (_parser.match<Num_t>(temp.back().substr(1))) { | ||
8358 | stopStatus = NumState::Negtive; | ||
8359 | } | ||
8360 | } else { | ||
8361 | if (_parser.match<Num_t>(temp.back())) { | ||
8362 | stopStatus = NumState::Positive; | ||
8363 | } | ||
8364 | } | ||
7901 | stopValue = std::move(temp.back()); | 8365 | stopValue = std::move(temp.back()); |
7902 | temp.pop_back(); | 8366 | temp.pop_back(); |
7903 | } | 8367 | } |
@@ -7919,8 +8383,33 @@ private: | |||
7919 | transformChainValue(chain, temp, ExpUsage::Closure); | 8383 | transformChainValue(chain, temp, ExpUsage::Closure); |
7920 | _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | 8384 | _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); |
7921 | } | 8385 | } |
8386 | if (startValue.empty()) { | ||
8387 | startValue = "1"s; | ||
8388 | startStatus = NumState::Positive; | ||
8389 | } | ||
8390 | std::string minVar; | ||
8391 | if (startStatus != NumState::Positive) { | ||
8392 | std::string prefix; | ||
8393 | if (!extraScope && !inClosure && needScope) { | ||
8394 | extraScope = true; | ||
8395 | prefix = indent() + "do"s + nll(x); | ||
8396 | pushScope(); | ||
8397 | } | ||
8398 | minVar = getUnusedName("_min_"sv); | ||
8399 | varBefore.push_back(minVar); | ||
8400 | if (startStatus == NumState::Negtive) { | ||
8401 | _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nll(nameList); | ||
8402 | } else { | ||
8403 | _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nll(nameList); | ||
8404 | } | ||
8405 | } | ||
8406 | bool defaultStop = false; | ||
8407 | if (stopValue.empty()) { | ||
8408 | stopValue = "#"s + listVar; | ||
8409 | defaultStop = true; | ||
8410 | } | ||
7922 | std::string maxVar; | 8411 | std::string maxVar; |
7923 | if (!stopValue.empty()) { | 8412 | if (stopStatus != NumState::Positive) { |
7924 | std::string prefix; | 8413 | std::string prefix; |
7925 | if (!extraScope && !inClosure && needScope) { | 8414 | if (!extraScope && !inClosure && needScope) { |
7926 | extraScope = true; | 8415 | extraScope = true; |
@@ -7929,14 +8418,45 @@ private: | |||
7929 | } | 8418 | } |
7930 | maxVar = getUnusedName("_max_"sv); | 8419 | maxVar = getUnusedName("_max_"sv); |
7931 | varBefore.push_back(maxVar); | 8420 | varBefore.push_back(maxVar); |
7932 | _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); | 8421 | if (stopStatus == NumState::Negtive) { |
8422 | _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nll(nameList); | ||
8423 | } else { | ||
8424 | _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); | ||
8425 | } | ||
8426 | } | ||
8427 | if (startStatus == NumState::Unknown) { | ||
8428 | _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nll(nameList); | ||
8429 | } | ||
8430 | if (!defaultStop && stopStatus == NumState::Unknown) { | ||
8431 | _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nll(nameList); | ||
7933 | } | 8432 | } |
7934 | _buf << indent() << "for "sv << indexVar << " = "sv; | 8433 | _buf << indent() << "for "sv << indexVar << " = "sv; |
7935 | _buf << startValue << ", "sv; | 8434 | if (startValue.empty()) { |
8435 | _buf << "1"sv; | ||
8436 | } else { | ||
8437 | switch (startStatus) { | ||
8438 | case NumState::Unknown: | ||
8439 | case NumState::Negtive: | ||
8440 | _buf << minVar; | ||
8441 | break; | ||
8442 | case NumState::Positive: | ||
8443 | _buf << startValue; | ||
8444 | break; | ||
8445 | } | ||
8446 | } | ||
8447 | _buf << ", "sv; | ||
7936 | if (stopValue.empty()) { | 8448 | if (stopValue.empty()) { |
7937 | _buf << "#"sv << listVar; | 8449 | _buf << "#"sv << listVar; |
7938 | } else { | 8450 | } else { |
7939 | _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; | 8451 | switch (stopStatus) { |
8452 | case NumState::Unknown: | ||
8453 | case NumState::Negtive: | ||
8454 | _buf << maxVar; | ||
8455 | break; | ||
8456 | case NumState::Positive: | ||
8457 | _buf << stopValue; | ||
8458 | break; | ||
8459 | } | ||
7940 | } | 8460 | } |
7941 | if (!stepValue.empty()) { | 8461 | if (!stepValue.empty()) { |
7942 | _buf << ", "sv << stepValue; | 8462 | _buf << ", "sv << stepValue; |
@@ -7976,7 +8496,7 @@ private: | |||
7976 | pushScope(); | 8496 | pushScope(); |
7977 | for (const auto& var : vars) forceAddToScope(var); | 8497 | for (const auto& var : vars) forceAddToScope(var); |
7978 | for (const auto& var : varAfter) addToScope(var); | 8498 | for (const auto& var : varAfter) addToScope(var); |
7979 | if (!varConstAfter.empty()) markVarConst(varConstAfter); | 8499 | if (!varConstAfter.empty()) markVarLocalConst(varConstAfter); |
7980 | if (!destructPairs.empty()) { | 8500 | if (!destructPairs.empty()) { |
7981 | temp.clear(); | 8501 | temp.clear(); |
7982 | for (auto& pair : destructPairs) { | 8502 | for (auto& pair : destructPairs) { |
@@ -8061,7 +8581,7 @@ private: | |||
8061 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); | 8581 | _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); |
8062 | pushScope(); | 8582 | pushScope(); |
8063 | forceAddToScope(varName); | 8583 | forceAddToScope(varName); |
8064 | markVarConst(varName); | 8584 | markVarLocalConst(varName); |
8065 | out.push_back(clearBuf()); | 8585 | out.push_back(clearBuf()); |
8066 | } | 8586 | } |
8067 | 8587 | ||
@@ -8069,26 +8589,59 @@ private: | |||
8069 | transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); | 8589 | transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); |
8070 | } | 8590 | } |
8071 | 8591 | ||
8072 | void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8592 | void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
8073 | switch (body->get_id()) { | 8593 | switch (bodyOrStmt->get_id()) { |
8074 | case id<Block_t>(): | 8594 | case id<Block_t>(): |
8075 | transformBlock(static_cast<Block_t*>(body), out, usage, assignList); | 8595 | transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList); |
8076 | break; | 8596 | break; |
8077 | case id<Statement_t>(): { | 8597 | case id<Statement_t>(): { |
8078 | auto newBlock = body->new_ptr<Block_t>(); | 8598 | auto newBlock = bodyOrStmt->new_ptr<Block_t>(); |
8079 | newBlock->statements.push_back(body); | 8599 | newBlock->statements.push_back(bodyOrStmt); |
8080 | transformBlock(newBlock, out, usage, assignList); | 8600 | transformBlock(newBlock, out, usage, assignList); |
8081 | break; | 8601 | break; |
8082 | } | 8602 | } |
8083 | default: YUEE("AST node mismatch", body); break; | 8603 | default: YUEE("AST node mismatch", bodyOrStmt); break; |
8084 | } | 8604 | } |
8085 | } | 8605 | } |
8086 | 8606 | ||
8087 | bool hasContinueStatement(ast_node* body) { | 8607 | enum class BreakLoopType { |
8088 | return traversal::Stop == body->traverse([&](ast_node* node) { | 8608 | None = 0, |
8609 | Break = 1, | ||
8610 | BreakWithValue = 1 << 1, | ||
8611 | Continue = 1 << 2 | ||
8612 | }; | ||
8613 | |||
8614 | bool hasBreak(uint32_t breakLoopType) const { | ||
8615 | return (breakLoopType & int(BreakLoopType::Break)) != 0; | ||
8616 | } | ||
8617 | |||
8618 | bool hasBreakWithValue(uint32_t breakLoopType) const { | ||
8619 | return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0; | ||
8620 | } | ||
8621 | |||
8622 | bool hasContinue(uint32_t breakLoopType) const { | ||
8623 | return (breakLoopType & int(BreakLoopType::Continue)) != 0; | ||
8624 | } | ||
8625 | |||
8626 | uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) { | ||
8627 | uint32_t type = 0; | ||
8628 | body->traverse([&](ast_node* node) { | ||
8089 | if (auto stmt = ast_cast<Statement_t>(node)) { | 8629 | if (auto stmt = ast_cast<Statement_t>(node)) { |
8090 | if (stmt->content.is<BreakLoop_t>()) { | 8630 | if (auto breakLoop = stmt->content.as<BreakLoop_t>()) { |
8091 | return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; | 8631 | if (breakLoop->type.is<Continue_t>()) { |
8632 | type |= int(BreakLoopType::Continue); | ||
8633 | return traversal::Return; | ||
8634 | } else { | ||
8635 | if (breakLoop->value) { | ||
8636 | if (varBWV.empty()) { | ||
8637 | throw CompileError("break with a value is not allowed here"sv, breakLoop->value); | ||
8638 | } | ||
8639 | type |= int(BreakLoopType::BreakWithValue); | ||
8640 | breakLoop->varBWV = varBWV; | ||
8641 | } else { | ||
8642 | type |= int(BreakLoopType::Break); | ||
8643 | } | ||
8644 | } | ||
8092 | } else if (auto expList = expListFrom(stmt)) { | 8645 | } else if (auto expList = expListFrom(stmt)) { |
8093 | BLOCK_START | 8646 | BLOCK_START |
8094 | auto value = singleValueFrom(expList); | 8647 | auto value = singleValueFrom(expList); |
@@ -8099,40 +8652,30 @@ private: | |||
8099 | switch (sVal->get_id()) { | 8652 | switch (sVal->get_id()) { |
8100 | case id<With_t>(): { | 8653 | case id<With_t>(): { |
8101 | auto withNode = static_cast<With_t*>(sVal); | 8654 | auto withNode = static_cast<With_t*>(sVal); |
8102 | if (hasContinueStatement(withNode->body)) { | 8655 | type |= getBreakLoopType(withNode->body, varBWV); |
8103 | return traversal::Stop; | 8656 | return traversal::Return; |
8104 | } | ||
8105 | break; | ||
8106 | } | 8657 | } |
8107 | case id<Do_t>(): { | 8658 | case id<Do_t>(): { |
8108 | auto doNode = static_cast<Do_t*>(sVal); | 8659 | auto doNode = static_cast<Do_t*>(sVal); |
8109 | if (hasContinueStatement(doNode->body)) { | 8660 | type |= getBreakLoopType(doNode->body, varBWV); |
8110 | return traversal::Stop; | 8661 | return traversal::Return; |
8111 | } | ||
8112 | break; | ||
8113 | } | 8662 | } |
8114 | case id<If_t>(): { | 8663 | case id<If_t>(): { |
8115 | auto ifNode = static_cast<If_t*>(sVal); | 8664 | auto ifNode = static_cast<If_t*>(sVal); |
8116 | for (auto n : ifNode->nodes.objects()) { | 8665 | for (auto n : ifNode->nodes.objects()) { |
8117 | if (hasContinueStatement(n)) { | 8666 | type |= getBreakLoopType(n, varBWV); |
8118 | return traversal::Stop; | ||
8119 | } | ||
8120 | } | 8667 | } |
8121 | break; | 8668 | return traversal::Return; |
8122 | } | 8669 | } |
8123 | case id<Switch_t>(): { | 8670 | case id<Switch_t>(): { |
8124 | auto switchNode = static_cast<Switch_t*>(sVal); | 8671 | auto switchNode = static_cast<Switch_t*>(sVal); |
8125 | for (auto branch : switchNode->branches.objects()) { | 8672 | for (auto branch : switchNode->branches.objects()) { |
8126 | if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { | 8673 | type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV); |
8127 | return traversal::Stop; | ||
8128 | } | ||
8129 | } | 8674 | } |
8130 | if (switchNode->lastBranch) { | 8675 | if (switchNode->lastBranch) { |
8131 | if (hasContinueStatement(switchNode->lastBranch)) { | 8676 | type |= getBreakLoopType(switchNode->lastBranch, varBWV); |
8132 | return traversal::Stop; | ||
8133 | } | ||
8134 | } | 8677 | } |
8135 | break; | 8678 | return traversal::Return; |
8136 | } | 8679 | } |
8137 | } | 8680 | } |
8138 | BLOCK_END | 8681 | BLOCK_END |
@@ -8146,6 +8689,7 @@ private: | |||
8146 | } | 8689 | } |
8147 | return traversal::Return; | 8690 | return traversal::Return; |
8148 | }); | 8691 | }); |
8692 | return type; | ||
8149 | } | 8693 | } |
8150 | 8694 | ||
8151 | void addDoToLastLineReturn(ast_node* body) { | 8695 | void addDoToLastLineReturn(ast_node* body) { |
@@ -8169,10 +8713,10 @@ private: | |||
8169 | } | 8713 | } |
8170 | } | 8714 | } |
8171 | 8715 | ||
8172 | void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8716 | void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) { |
8173 | str_list temp; | 8717 | str_list temp; |
8174 | bool extraDo = false; | 8718 | bool extraDo = false; |
8175 | bool withContinue = hasContinueStatement(body); | 8719 | bool withContinue = hasContinue(breakLoopType); |
8176 | int target = getLuaTarget(body); | 8720 | int target = getLuaTarget(body); |
8177 | std::string extraLabel; | 8721 | std::string extraLabel; |
8178 | if (withContinue) { | 8722 | if (withContinue) { |
@@ -8181,7 +8725,7 @@ private: | |||
8181 | if (!block->statements.empty()) { | 8725 | if (!block->statements.empty()) { |
8182 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8726 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
8183 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8727 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
8184 | extraDo = _parser.toString(breakLoop) == "break"sv; | 8728 | extraDo = breakLoop->type.is<Break_t>(); |
8185 | } | 8729 | } |
8186 | } | 8730 | } |
8187 | } | 8731 | } |
@@ -8214,9 +8758,6 @@ private: | |||
8214 | popScope(); | 8758 | popScope(); |
8215 | _buf << indent() << "end"sv << nll(body); | 8759 | _buf << indent() << "end"sv << nll(body); |
8216 | } | 8760 | } |
8217 | if (!appendContent.empty()) { | ||
8218 | _buf << indent() << appendContent; | ||
8219 | } | ||
8220 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | 8761 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); |
8221 | popScope(); | 8762 | popScope(); |
8222 | _buf << indent() << "until true"sv << nlr(body); | 8763 | _buf << indent() << "until true"sv << nlr(body); |
@@ -8226,14 +8767,9 @@ private: | |||
8226 | temp.push_back(clearBuf()); | 8767 | temp.push_back(clearBuf()); |
8227 | _continueVars.pop(); | 8768 | _continueVars.pop(); |
8228 | } else { | 8769 | } else { |
8229 | if (!appendContent.empty()) { | ||
8230 | temp.push_back(indent() + appendContent); | ||
8231 | } | ||
8232 | temp.push_back(extraLabel); | 8770 | temp.push_back(extraLabel); |
8233 | _continueVars.pop(); | 8771 | _continueVars.pop(); |
8234 | } | 8772 | } |
8235 | } else if (!appendContent.empty()) { | ||
8236 | temp.back().append(indent() + appendContent); | ||
8237 | } | 8773 | } |
8238 | out.push_back(join(temp)); | 8774 | out.push_back(join(temp)); |
8239 | } | 8775 | } |
@@ -8241,8 +8777,9 @@ private: | |||
8241 | std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { | 8777 | std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { |
8242 | str_list temp; | 8778 | str_list temp; |
8243 | bool extraDo = false; | 8779 | bool extraDo = false; |
8244 | auto body = repeatNode->body->content.get(); | 8780 | auto body = repeatNode->body.get(); |
8245 | bool withContinue = hasContinueStatement(body); | 8781 | auto breakLoopType = getBreakLoopType(body, Empty); |
8782 | bool withContinue = hasContinue(breakLoopType); | ||
8246 | std::string conditionVar; | 8783 | std::string conditionVar; |
8247 | std::string extraLabel; | 8784 | std::string extraLabel; |
8248 | ast_ptr<false, ExpListAssign_t> condAssign; | 8785 | ast_ptr<false, ExpListAssign_t> condAssign; |
@@ -8253,7 +8790,7 @@ private: | |||
8253 | if (!block->statements.empty()) { | 8790 | if (!block->statements.empty()) { |
8254 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 8791 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
8255 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 8792 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
8256 | extraDo = _parser.toString(breakLoop) == "break"sv; | 8793 | extraDo = breakLoop->type.is<Break_t>(); |
8257 | } | 8794 | } |
8258 | } | 8795 | } |
8259 | } | 8796 | } |
@@ -8316,7 +8853,8 @@ private: | |||
8316 | void transformFor(For_t* forNode, str_list& out) { | 8853 | void transformFor(For_t* forNode, str_list& out) { |
8317 | str_list temp; | 8854 | str_list temp; |
8318 | transformForHead(forNode, temp); | 8855 | transformForHead(forNode, temp); |
8319 | transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); | 8856 | auto breakLoopType = getBreakLoopType(forNode->body, Empty); |
8857 | transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); | ||
8320 | popScope(); | 8858 | popScope(); |
8321 | out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); | 8859 | out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); |
8322 | } | 8860 | } |
@@ -8327,13 +8865,24 @@ private: | |||
8327 | addToScope(accum); | 8865 | addToScope(accum); |
8328 | std::string len = getUnusedName("_len_"sv); | 8866 | std::string len = getUnusedName("_len_"sv); |
8329 | addToScope(len); | 8867 | addToScope(len); |
8330 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); | 8868 | auto breakLoopType = getBreakLoopType(forNode->body, accum); |
8869 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); | ||
8870 | out.emplace_back(clearBuf()); | ||
8331 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); | 8871 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); |
8332 | out.push_back(clearBuf()); | 8872 | auto& lenAssign = out.emplace_back(clearBuf()); |
8333 | transformForHead(forNode, out); | 8873 | transformForHead(forNode, out); |
8334 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 8874 | if (hasBreakWithValue(breakLoopType)) { |
8335 | auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); | 8875 | lenAssign.clear(); |
8336 | transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); | 8876 | transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common); |
8877 | } else { | ||
8878 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | ||
8879 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body); | ||
8880 | expList->followStmt = followStmt.get(); | ||
8881 | transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList); | ||
8882 | if (!expList->followStmtProcessed) { | ||
8883 | lenAssign.clear(); | ||
8884 | } | ||
8885 | } | ||
8337 | popScope(); | 8886 | popScope(); |
8338 | out.push_back(indent() + "end"s + nlr(forNode)); | 8887 | out.push_back(indent() + "end"s + nlr(forNode)); |
8339 | return accum; | 8888 | return accum; |
@@ -8412,7 +8961,8 @@ private: | |||
8412 | void transformForEach(ForEach_t* forEach, str_list& out) { | 8961 | void transformForEach(ForEach_t* forEach, str_list& out) { |
8413 | str_list temp; | 8962 | str_list temp; |
8414 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); | 8963 | bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); |
8415 | transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); | 8964 | auto breakLoopType = getBreakLoopType(forEach->body, Empty); |
8965 | transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); | ||
8416 | popScope(); | 8966 | popScope(); |
8417 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); | 8967 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); |
8418 | if (extraScoped) { | 8968 | if (extraScoped) { |
@@ -8427,13 +8977,24 @@ private: | |||
8427 | addToScope(accum); | 8977 | addToScope(accum); |
8428 | std::string len = getUnusedName("_len_"sv); | 8978 | std::string len = getUnusedName("_len_"sv); |
8429 | addToScope(len); | 8979 | addToScope(len); |
8430 | _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); | 8980 | auto breakLoopType = getBreakLoopType(forEach->body, accum); |
8981 | _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); | ||
8982 | out.emplace_back(clearBuf()); | ||
8431 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); | 8983 | _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); |
8432 | out.push_back(clearBuf()); | 8984 | auto& lenAssign = out.emplace_back(clearBuf()); |
8433 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); | 8985 | transformForEachHead(forEach->nameList, forEach->loopValue, out, true); |
8434 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | 8986 | if (hasBreakWithValue(breakLoopType)) { |
8435 | auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); | 8987 | lenAssign.clear(); |
8436 | transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); | 8988 | transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common); |
8989 | } else { | ||
8990 | auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); | ||
8991 | auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body); | ||
8992 | expList->followStmt = followStmt.get(); | ||
8993 | transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList); | ||
8994 | if (!expList->followStmtProcessed) { | ||
8995 | lenAssign.clear(); | ||
8996 | } | ||
8997 | } | ||
8437 | popScope(); | 8998 | popScope(); |
8438 | out.push_back(indent() + "end"s + nlr(forEach)); | 8999 | out.push_back(indent() + "end"s + nlr(forEach)); |
8439 | return accum; | 9000 | return accum; |
@@ -8617,12 +9178,64 @@ private: | |||
8617 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); | 9178 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); |
8618 | } | 9179 | } |
8619 | 9180 | ||
9181 | void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) { | ||
9182 | std::optional<std::string> indent; | ||
9183 | str_list temp; | ||
9184 | for (auto line_ : multiline->lines.objects()) { | ||
9185 | auto line = static_cast<YAMLLine_t*>(line_); | ||
9186 | auto indentStr = _parser.toString(line->indent); | ||
9187 | if (!indent) { | ||
9188 | indent = indentStr; | ||
9189 | } | ||
9190 | if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) { | ||
9191 | throw CompileError("inconsistent indent"sv, line); | ||
9192 | } | ||
9193 | indentStr = indentStr.substr(indent.value().size()); | ||
9194 | str_list segs; | ||
9195 | bool firstSeg = true; | ||
9196 | for (auto seg_ : line->segments.objects()) { | ||
9197 | auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get(); | ||
9198 | switch (content->get_id()) { | ||
9199 | case id<YAMLLineInner_t>(): { | ||
9200 | auto seqStr = _parser.toString(content); | ||
9201 | Utils::replace(seqStr, "\\#"sv, "#"sv); | ||
9202 | if (firstSeg) { | ||
9203 | firstSeg = false; | ||
9204 | seqStr.insert(0, indentStr); | ||
9205 | } | ||
9206 | segs.push_back(Utils::toLuaDoubleString(seqStr)); | ||
9207 | break; | ||
9208 | } | ||
9209 | case id<Exp_t>(): { | ||
9210 | if (firstSeg) { | ||
9211 | firstSeg = false; | ||
9212 | if (!indentStr.empty()) { | ||
9213 | segs.push_back(Utils::toLuaDoubleString(indentStr)); | ||
9214 | } | ||
9215 | } | ||
9216 | transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure); | ||
9217 | segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')'; | ||
9218 | break; | ||
9219 | } | ||
9220 | default: YUEE("AST node mismatch", content); break; | ||
9221 | } | ||
9222 | } | ||
9223 | temp.push_back(join(segs, " .. "sv)); | ||
9224 | } | ||
9225 | auto str = join(temp, " .. '\\n' .. "sv); | ||
9226 | Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv); | ||
9227 | Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv); | ||
9228 | Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv); | ||
9229 | out.push_back(str); | ||
9230 | } | ||
9231 | |||
8620 | void transformString(String_t* string, str_list& out) { | 9232 | void transformString(String_t* string, str_list& out) { |
8621 | auto str = string->str.get(); | 9233 | auto str = string->str.get(); |
8622 | switch (str->get_id()) { | 9234 | switch (str->get_id()) { |
8623 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; | 9235 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; |
8624 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; | 9236 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; |
8625 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; | 9237 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; |
9238 | case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break; | ||
8626 | default: YUEE("AST node mismatch", str); break; | 9239 | default: YUEE("AST node mismatch", str); break; |
8627 | } | 9240 | } |
8628 | } | 9241 | } |
@@ -8804,7 +9417,7 @@ private: | |||
8804 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); | 9417 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); |
8805 | for (const auto& name : names) { | 9418 | for (const auto& name : names) { |
8806 | forceAddToScope(name.first); | 9419 | forceAddToScope(name.first); |
8807 | markVarConst(name.first); | 9420 | markVarLocalConst(name.first); |
8808 | varDefs.push_back(name.first); | 9421 | varDefs.push_back(name.first); |
8809 | classConstVars.push_back(name.first); | 9422 | classConstVars.push_back(name.first); |
8810 | } | 9423 | } |
@@ -8818,7 +9431,7 @@ private: | |||
8818 | for (const auto& item : destruct.items) { | 9431 | for (const auto& item : destruct.items) { |
8819 | if (!item.targetVar.empty()) { | 9432 | if (!item.targetVar.empty()) { |
8820 | forceAddToScope(item.targetVar); | 9433 | forceAddToScope(item.targetVar); |
8821 | markVarConst(item.targetVar); | 9434 | markVarLocalConst(item.targetVar); |
8822 | varDefs.push_back(item.targetVar); | 9435 | varDefs.push_back(item.targetVar); |
8823 | classConstVars.push_back(item.targetVar); | 9436 | classConstVars.push_back(item.targetVar); |
8824 | } | 9437 | } |
@@ -9200,11 +9813,11 @@ private: | |||
9200 | std::string withVar; | 9813 | std::string withVar; |
9201 | bool needScope = !currentScope().lastStatement && !returnValue; | 9814 | bool needScope = !currentScope().lastStatement && !returnValue; |
9202 | bool extraScope = false; | 9815 | bool extraScope = false; |
9203 | if (with->assigns) { | 9816 | if (with->assign) { |
9204 | auto vars = getAssignVars(with); | 9817 | auto vars = getAssignVars(with); |
9205 | if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { | 9818 | if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { |
9206 | if (with->assigns->values.objects().size() == 1) { | 9819 | if (with->assign->values.objects().size() == 1) { |
9207 | auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); | 9820 | auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read); |
9208 | if (!var.empty() && isLocal(var)) { | 9821 | if (!var.empty() && isLocal(var)) { |
9209 | withVar = var; | 9822 | withVar = var; |
9210 | } | 9823 | } |
@@ -9214,7 +9827,7 @@ private: | |||
9214 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 9827 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
9215 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); | 9828 | assignment->expList.set(toAst<ExpList_t>(withVar, x)); |
9216 | auto assign = x->new_ptr<Assign_t>(); | 9829 | auto assign = x->new_ptr<Assign_t>(); |
9217 | assign->values.push_back(with->assigns->values.objects().front()); | 9830 | assign->values.push_back(with->assign->values.objects().front()); |
9218 | assignment->action.set(assign); | 9831 | assignment->action.set(assign); |
9219 | if (needScope) { | 9832 | if (needScope) { |
9220 | extraScope = true; | 9833 | extraScope = true; |
@@ -9228,7 +9841,7 @@ private: | |||
9228 | auto assign = x->new_ptr<Assign_t>(); | 9841 | auto assign = x->new_ptr<Assign_t>(); |
9229 | assign->values.push_back(toAst<Exp_t>(withVar, x)); | 9842 | assign->values.push_back(toAst<Exp_t>(withVar, x)); |
9230 | bool skipFirst = true; | 9843 | bool skipFirst = true; |
9231 | for (auto value : with->assigns->values.objects()) { | 9844 | for (auto value : with->assign->values.objects()) { |
9232 | if (skipFirst) { | 9845 | if (skipFirst) { |
9233 | skipFirst = false; | 9846 | skipFirst = false; |
9234 | continue; | 9847 | continue; |
@@ -9241,7 +9854,7 @@ private: | |||
9241 | withVar = vars.front(); | 9854 | withVar = vars.front(); |
9242 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 9855 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
9243 | assignment->expList.set(with->valueList); | 9856 | assignment->expList.set(with->valueList); |
9244 | assignment->action.set(with->assigns); | 9857 | assignment->action.set(with->assign); |
9245 | if (needScope) { | 9858 | if (needScope) { |
9246 | extraScope = true; | 9859 | extraScope = true; |
9247 | temp.push_back(indent() + "do"s + nll(with)); | 9860 | temp.push_back(indent() + "do"s + nll(with)); |
@@ -9319,15 +9932,57 @@ private: | |||
9319 | } | 9932 | } |
9320 | } | 9933 | } |
9321 | _withVars.push(withVar); | 9934 | _withVars.push(withVar); |
9935 | std::string breakWithVar; | ||
9936 | if (assignList || returnValue) { | ||
9937 | auto breakLoopType = getBreakLoopType(with->body, withVar); | ||
9938 | if (hasBreakWithValue(breakLoopType)) { | ||
9939 | breakWithVar = withVar; | ||
9940 | } | ||
9941 | } | ||
9322 | if (with->eop) { | 9942 | if (with->eop) { |
9323 | auto ifNode = x->new_ptr<If_t>(); | 9943 | auto ifNode = x->new_ptr<If_t>(); |
9324 | ifNode->type.set(toAst<IfType_t>("if"sv, x)); | 9944 | ifNode->type.set(toAst<IfType_t>("if"sv, x)); |
9325 | ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); | 9945 | ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); |
9326 | ifNode->nodes.push_back(with->body); | 9946 | ifNode->nodes.push_back(with->body); |
9327 | transformIf(ifNode, temp, ExpUsage::Common); | 9947 | if (breakWithVar.empty()) { |
9948 | transformIf(ifNode, temp, ExpUsage::Common); | ||
9949 | } else { | ||
9950 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
9951 | simpleValue->value.set(ifNode); | ||
9952 | auto exp = newExp(simpleValue, x); | ||
9953 | auto expList = x->new_ptr<ExpList_t>(); | ||
9954 | expList->exprs.push_back(exp); | ||
9955 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
9956 | expListAssign->expList.set(expList); | ||
9957 | auto stmt = x->new_ptr<Statement_t>(); | ||
9958 | stmt->content.set(expListAssign); | ||
9959 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); | ||
9960 | auto block = x->new_ptr<Block_t>(); | ||
9961 | block->statements.push_back(stmt); | ||
9962 | repeatNode->body.set(block); | ||
9963 | auto sVal = x->new_ptr<SimpleValue_t>(); | ||
9964 | sVal->value.set(repeatNode); | ||
9965 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); | ||
9966 | transformAssignment(asmt, temp); | ||
9967 | } | ||
9328 | } else { | 9968 | } else { |
9329 | bool transformed = false; | 9969 | bool transformed = false; |
9330 | if (!extraScope && assignList) { | 9970 | if (!breakWithVar.empty()) { |
9971 | auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x); | ||
9972 | auto block = x->new_ptr<Block_t>(); | ||
9973 | if (auto blk = with->body.as<Block_t>()) { | ||
9974 | block->statements.dup(blk->statements); | ||
9975 | } else { | ||
9976 | auto stmt = with->body.to<Statement_t>(); | ||
9977 | block->statements.push_back(stmt); | ||
9978 | } | ||
9979 | repeatNode->body.set(block); | ||
9980 | auto sVal = x->new_ptr<SimpleValue_t>(); | ||
9981 | sVal->value.set(repeatNode); | ||
9982 | auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); | ||
9983 | transformAssignment(asmt, temp); | ||
9984 | transformed = true; | ||
9985 | } else if (!extraScope && assignList) { | ||
9331 | if (auto block = with->body.as<Block_t>()) { | 9986 | if (auto block = with->body.as<Block_t>()) { |
9332 | if (!block->statements.empty()) { | 9987 | if (!block->statements.empty()) { |
9333 | Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); | 9988 | Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); |
@@ -9392,12 +10047,18 @@ private: | |||
9392 | switch (item->get_id()) { | 10047 | switch (item->get_id()) { |
9393 | case id<ClassDecl_t>(): { | 10048 | case id<ClassDecl_t>(): { |
9394 | auto classDecl = static_cast<ClassDecl_t*>(item); | 10049 | auto classDecl = static_cast<ClassDecl_t*>(item); |
10050 | std::string varName; | ||
9395 | if (classDecl->name) { | 10051 | if (classDecl->name) { |
9396 | if (auto var = classDecl->name->item.as<Variable_t>()) { | 10052 | if (auto var = classDecl->name->item.as<Variable_t>()) { |
9397 | addGlobalVar(variableToString(var), classDecl->name->item); | 10053 | varName = variableToString(var); |
10054 | addGlobalVar(varName, var); | ||
9398 | } | 10055 | } |
9399 | } | 10056 | } |
10057 | if (varName.empty()) { | ||
10058 | throw CompileError("missing name for class", classDecl); | ||
10059 | } | ||
9400 | transformClassDecl(classDecl, out, ExpUsage::Common); | 10060 | transformClassDecl(classDecl, out, ExpUsage::Common); |
10061 | markVarGlobalConst(varName); | ||
9401 | break; | 10062 | break; |
9402 | } | 10063 | } |
9403 | case id<GlobalOp_t>(): | 10064 | case id<GlobalOp_t>(): |
@@ -9411,9 +10072,11 @@ private: | |||
9411 | auto values = global->item.to<GlobalValues_t>(); | 10072 | auto values = global->item.to<GlobalValues_t>(); |
9412 | if (values->valueList) { | 10073 | if (values->valueList) { |
9413 | auto expList = x->new_ptr<ExpList_t>(); | 10074 | auto expList = x->new_ptr<ExpList_t>(); |
10075 | str_list varNames; | ||
9414 | for (auto name : values->nameList->names.objects()) { | 10076 | for (auto name : values->nameList->names.objects()) { |
9415 | auto var = static_cast<Variable_t*>(name); | 10077 | auto var = static_cast<Variable_t*>(name); |
9416 | addGlobalVar(variableToString(var), var); | 10078 | varNames.emplace_back(variableToString(var)); |
10079 | addGlobalVar(varNames.back(), var); | ||
9417 | auto callable = x->new_ptr<Callable_t>(); | 10080 | auto callable = x->new_ptr<Callable_t>(); |
9418 | callable->item.set(name); | 10081 | callable->item.set(name); |
9419 | auto chainValue = x->new_ptr<ChainValue_t>(); | 10082 | auto chainValue = x->new_ptr<ChainValue_t>(); |
@@ -9432,10 +10095,17 @@ private: | |||
9432 | } | 10095 | } |
9433 | assignment->action.set(assign); | 10096 | assignment->action.set(assign); |
9434 | transformAssignment(assignment, out); | 10097 | transformAssignment(assignment, out); |
10098 | for (const auto& name : varNames) { | ||
10099 | markVarGlobalConst(name); | ||
10100 | } | ||
9435 | } else { | 10101 | } else { |
9436 | for (auto name : values->nameList->names.objects()) { | 10102 | for (auto name : values->nameList->names.objects()) { |
9437 | auto var = static_cast<Variable_t*>(name); | 10103 | auto var = static_cast<Variable_t*>(name); |
9438 | addGlobalVar(variableToString(var), var); | 10104 | auto varName = variableToString(var); |
10105 | addGlobalVar(varName, var); | ||
10106 | if (global->constAttrib) { | ||
10107 | markVarGlobalConst(varName); | ||
10108 | } | ||
9439 | } | 10109 | } |
9440 | } | 10110 | } |
9441 | break; | 10111 | break; |
@@ -9784,8 +10454,47 @@ private: | |||
9784 | out.push_back(join(temp)); | 10454 | out.push_back(join(temp)); |
9785 | } | 10455 | } |
9786 | 10456 | ||
9787 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { | 10457 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
9788 | auto x = tryNode; | 10458 | auto x = tryNode; |
10459 | if (tryNode->eop && usage == ExpUsage::Assignment) { | ||
10460 | str_list rets; | ||
10461 | pushScope(); | ||
10462 | auto okVar = getUnusedName("_ok_"sv); | ||
10463 | for (size_t i = 0; i < assignList->exprs.size(); i++) { | ||
10464 | auto retVar = getUnusedName("_ret_"sv); | ||
10465 | rets.emplace_back(retVar); | ||
10466 | addToScope(retVar); | ||
10467 | } | ||
10468 | popScope(); | ||
10469 | auto varList = join(rets, ","sv); | ||
10470 | auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x); | ||
10471 | auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front(); | ||
10472 | auto sVal = simpleSingleValueFrom(exp); | ||
10473 | auto newTry = sVal->value.to<Try_t>(); | ||
10474 | newTry->func.set(tryNode->func); | ||
10475 | newTry->catchBlock.set(tryNode->catchBlock); | ||
10476 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
10477 | assignment->expList.set(assignList); | ||
10478 | auto assign = x->new_ptr<Assign_t>(); | ||
10479 | assign->values.push_back(ifNode); | ||
10480 | assignment->action.set(assign); | ||
10481 | transformAssignment(assignment, out); | ||
10482 | return; | ||
10483 | } | ||
10484 | if (tryNode->eop && usage != ExpUsage::Common) { | ||
10485 | auto okVar = getUnusedName("_ok_"sv); | ||
10486 | auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; | ||
10487 | auto doNode = toAst<Do_t>(code, x); | ||
10488 | auto block = doNode->body->content.to<Block_t>(); | ||
10489 | auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>(); | ||
10490 | auto assign = asmt->action.to<Assign_t>(); | ||
10491 | auto sVal = simpleSingleValueFrom(assign->values.back()); | ||
10492 | auto newTry = sVal->value.to<Try_t>(); | ||
10493 | newTry->func.set(tryNode->func); | ||
10494 | newTry->catchBlock.set(tryNode->catchBlock); | ||
10495 | transformDo(doNode, out, usage); | ||
10496 | return; | ||
10497 | } | ||
9789 | ast_ptr<true, Exp_t> errHandler; | 10498 | ast_ptr<true, Exp_t> errHandler; |
9790 | if (tryNode->catchBlock) { | 10499 | if (tryNode->catchBlock) { |
9791 | auto catchBlock = tryNode->catchBlock.get(); | 10500 | auto catchBlock = tryNode->catchBlock.get(); |
@@ -10097,7 +10806,7 @@ private: | |||
10097 | out.push_back(join(temp)); | 10806 | out.push_back(join(temp)); |
10098 | auto vars = getAssignVars(assignment); | 10807 | auto vars = getAssignVars(assignment); |
10099 | for (const auto& var : vars) { | 10808 | for (const auto& var : vars) { |
10100 | markVarConst(var); | 10809 | markVarLocalConst(var); |
10101 | } | 10810 | } |
10102 | } | 10811 | } |
10103 | 10812 | ||
@@ -10325,12 +11034,36 @@ private: | |||
10325 | transformAssignment(assignment, out); | 11034 | transformAssignment(assignment, out); |
10326 | if (auto var = ast_cast<Variable_t>(target)) { | 11035 | if (auto var = ast_cast<Variable_t>(target)) { |
10327 | auto moduleName = variableToString(var); | 11036 | auto moduleName = variableToString(var); |
10328 | markVarConst(moduleName); | 11037 | markVarLocalConst(moduleName); |
10329 | } else { | 11038 | } else { |
10330 | markDestructureConst(assignment); | 11039 | markDestructureConst(assignment); |
10331 | } | 11040 | } |
10332 | } | 11041 | } |
10333 | 11042 | ||
11043 | void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) { | ||
11044 | auto uname = static_cast<UnicodeName_t*>(importNode->segs.front()); | ||
11045 | auto var = _parser.toString(uname); | ||
11046 | auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var); | ||
11047 | auto varName = unicodeVariableFrom(uname); | ||
11048 | str_list temp; | ||
11049 | auto it = ++importNode->segs.objects().begin(); | ||
11050 | for (; it != importNode->segs.objects().end(); ++it) { | ||
11051 | temp.emplace_back(_parser.toString(*it)); | ||
11052 | } | ||
11053 | temp.emplace_front(var); | ||
11054 | if (isLocal(varName) || !isNormal) { | ||
11055 | temp.emplace_front("_G"s); | ||
11056 | } | ||
11057 | std::string stmt; | ||
11058 | if (importNode->target) { | ||
11059 | stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv); | ||
11060 | } else { | ||
11061 | stmt = "const "s + temp.back() + '=' + join(temp, "."sv); | ||
11062 | } | ||
11063 | auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode); | ||
11064 | transformLocalAttrib(localAttrib, out); | ||
11065 | } | ||
11066 | |||
10334 | void transformImport(Import_t* import, str_list& out) { | 11067 | void transformImport(Import_t* import, str_list& out) { |
10335 | auto content = import->content.get(); | 11068 | auto content = import->content.get(); |
10336 | switch (content->get_id()) { | 11069 | switch (content->get_id()) { |
@@ -10343,6 +11076,9 @@ private: | |||
10343 | case id<FromImport_t>(): | 11076 | case id<FromImport_t>(): |
10344 | transformFromImport(static_cast<FromImport_t*>(content), out); | 11077 | transformFromImport(static_cast<FromImport_t*>(content), out); |
10345 | break; | 11078 | break; |
11079 | case id<ImportGlobal_t>(): | ||
11080 | transformImportGlobal(static_cast<ImportGlobal_t*>(content), out); | ||
11081 | break; | ||
10346 | default: YUEE("AST node mismatch", content); break; | 11082 | default: YUEE("AST node mismatch", content); break; |
10347 | } | 11083 | } |
10348 | } | 11084 | } |
@@ -10362,15 +11098,27 @@ private: | |||
10362 | addToScope(accumVar); | 11098 | addToScope(accumVar); |
10363 | auto lenVar = getUnusedName("_len_"sv); | 11099 | auto lenVar = getUnusedName("_len_"sv); |
10364 | addToScope(lenVar); | 11100 | addToScope(lenVar); |
10365 | temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); | 11101 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
10366 | temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | 11102 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); |
11103 | temp.emplace_back(clearBuf()); | ||
11104 | _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); | ||
11105 | auto& lenAssign = temp.emplace_back(clearBuf()); | ||
10367 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11106 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
10368 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11107 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
10369 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 11108 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); |
10370 | pushScope(); | 11109 | pushScope(); |
10371 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | 11110 | if (hasBreakWithValue(breakLoopType)) { |
10372 | auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); | 11111 | lenAssign.clear(); |
10373 | transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); | 11112 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); |
11113 | } else { | ||
11114 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
11115 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode); | ||
11116 | assignLeft->followStmt = followStmt.get(); | ||
11117 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
11118 | if (!assignLeft->followStmtProcessed) { | ||
11119 | lenAssign.clear(); | ||
11120 | } | ||
11121 | } | ||
10374 | popScope(); | 11122 | popScope(); |
10375 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 11123 | temp.push_back(indent() + "end"s + nlr(whileNode)); |
10376 | if (expList) { | 11124 | if (expList) { |
@@ -10406,15 +11154,26 @@ private: | |||
10406 | addToScope(accumVar); | 11154 | addToScope(accumVar); |
10407 | auto lenVar = getUnusedName("_len_"sv); | 11155 | auto lenVar = getUnusedName("_len_"sv); |
10408 | addToScope(lenVar); | 11156 | addToScope(lenVar); |
10409 | temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); | 11157 | auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); |
10410 | temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | 11158 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); |
11159 | temp.emplace_back(clearBuf()); | ||
11160 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); | ||
10411 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11161 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
10412 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11162 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
10413 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); | 11163 | temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); |
10414 | pushScope(); | 11164 | pushScope(); |
10415 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | 11165 | if (hasBreakWithValue(breakLoopType)) { |
10416 | auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); | 11166 | lenAssign.clear(); |
10417 | transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); | 11167 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); |
11168 | } else { | ||
11169 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
11170 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode); | ||
11171 | assignLeft->followStmt = followStmt.get(); | ||
11172 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
11173 | if (!assignLeft->followStmtProcessed) { | ||
11174 | lenAssign.clear(); | ||
11175 | } | ||
11176 | } | ||
10418 | popScope(); | 11177 | popScope(); |
10419 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 11178 | temp.push_back(indent() + "end"s + nlr(whileNode)); |
10420 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); | 11179 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); |
@@ -10449,9 +11208,7 @@ private: | |||
10449 | expListAssign->expList.set(expList); | 11208 | expListAssign->expList.set(expList); |
10450 | auto stmt = x->new_ptr<Statement_t>(); | 11209 | auto stmt = x->new_ptr<Statement_t>(); |
10451 | stmt->content.set(expListAssign); | 11210 | stmt->content.set(expListAssign); |
10452 | auto body = x->new_ptr<Body_t>(); | 11211 | repeat->body.set(stmt); |
10453 | body->content.set(stmt); | ||
10454 | repeat->body.set(body); | ||
10455 | transformRepeat(repeat, out); | 11212 | transformRepeat(repeat, out); |
10456 | return; | 11213 | return; |
10457 | } | 11214 | } |
@@ -10459,7 +11216,8 @@ private: | |||
10459 | pushScope(); | 11216 | pushScope(); |
10460 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; | 11217 | bool isUntil = _parser.toString(whileNode->type) == "until"sv; |
10461 | auto condStr = transformCondExp(whileNode->condition, isUntil); | 11218 | auto condStr = transformCondExp(whileNode->condition, isUntil); |
10462 | transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); | 11219 | auto breakLoopType = getBreakLoopType(whileNode->body, Empty); |
11220 | transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); | ||
10463 | popScope(); | 11221 | popScope(); |
10464 | _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); | 11222 | _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); |
10465 | _buf << temp.back(); | 11223 | _buf << temp.back(); |
@@ -10467,6 +11225,106 @@ private: | |||
10467 | out.push_back(clearBuf()); | 11225 | out.push_back(clearBuf()); |
10468 | } | 11226 | } |
10469 | 11227 | ||
11228 | void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) { | ||
11229 | auto x = repeatNode; | ||
11230 | str_list temp; | ||
11231 | bool extraScope = false; | ||
11232 | if (expList) { | ||
11233 | if (!currentScope().lastStatement) { | ||
11234 | extraScope = true; | ||
11235 | temp.push_back(indent() + "do"s + nll(repeatNode)); | ||
11236 | pushScope(); | ||
11237 | } | ||
11238 | } | ||
11239 | auto accumVar = getUnusedName("_accum_"sv); | ||
11240 | addToScope(accumVar); | ||
11241 | auto lenVar = getUnusedName("_len_"sv); | ||
11242 | addToScope(lenVar); | ||
11243 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
11244 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode); | ||
11245 | temp.emplace_back(clearBuf()); | ||
11246 | _buf << indent() << "local "s << lenVar << " = 1"s << nll(repeatNode); | ||
11247 | auto& lenAssign = temp.emplace_back(clearBuf()); | ||
11248 | auto condStr = transformCondExp(repeatNode->condition, false); | ||
11249 | temp.push_back(indent() + "repeat"s + nll(repeatNode)); | ||
11250 | pushScope(); | ||
11251 | if (hasBreakWithValue(breakLoopType)) { | ||
11252 | lenAssign.clear(); | ||
11253 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common); | ||
11254 | } else { | ||
11255 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
11256 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode); | ||
11257 | assignLeft->followStmt = followStmt.get(); | ||
11258 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
11259 | if (!assignLeft->followStmtProcessed) { | ||
11260 | lenAssign.clear(); | ||
11261 | } | ||
11262 | } | ||
11263 | popScope(); | ||
11264 | temp.push_back(indent() + "until "s + condStr + nlr(repeatNode)); | ||
11265 | if (expList) { | ||
11266 | auto assign = x->new_ptr<Assign_t>(); | ||
11267 | assign->values.push_back(toAst<Exp_t>(accumVar, x)); | ||
11268 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
11269 | assignment->expList.set(expList); | ||
11270 | assignment->action.set(assign); | ||
11271 | transformAssignment(assignment, temp); | ||
11272 | if (extraScope) popScope(); | ||
11273 | } else { | ||
11274 | temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode)); | ||
11275 | } | ||
11276 | if (expList && extraScope) { | ||
11277 | temp.push_back(indent() + "end"s + nlr(repeatNode)); | ||
11278 | } | ||
11279 | out.push_back(join(temp)); | ||
11280 | } | ||
11281 | |||
11282 | void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) { | ||
11283 | auto x = repeatNode; | ||
11284 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
11285 | simpleValue->value.set(repeatNode); | ||
11286 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
11287 | return; | ||
11288 | } | ||
11289 | str_list temp; | ||
11290 | pushAnonFunctionScope(); | ||
11291 | pushAnonVarArg(); | ||
11292 | std::string& funcStart = temp.emplace_back(); | ||
11293 | pushScope(); | ||
11294 | auto accumVar = getUnusedName("_accum_"sv); | ||
11295 | addToScope(accumVar); | ||
11296 | auto lenVar = getUnusedName("_len_"sv); | ||
11297 | addToScope(lenVar); | ||
11298 | auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); | ||
11299 | _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode); | ||
11300 | temp.emplace_back(clearBuf()); | ||
11301 | auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(repeatNode)); | ||
11302 | auto condStr = transformCondExp(repeatNode->condition, false); | ||
11303 | temp.push_back(indent() + "repeat"s + nll(repeatNode)); | ||
11304 | pushScope(); | ||
11305 | if (hasBreakWithValue(breakLoopType)) { | ||
11306 | lenAssign.clear(); | ||
11307 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common); | ||
11308 | } else { | ||
11309 | auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); | ||
11310 | auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode); | ||
11311 | assignLeft->followStmt = followStmt.get(); | ||
11312 | transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft); | ||
11313 | if (!assignLeft->followStmtProcessed) { | ||
11314 | lenAssign.clear(); | ||
11315 | } | ||
11316 | } | ||
11317 | popScope(); | ||
11318 | temp.push_back(indent() + "until "s + condStr + nlr(repeatNode)); | ||
11319 | temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode)); | ||
11320 | popScope(); | ||
11321 | funcStart = anonFuncStart() + nll(repeatNode); | ||
11322 | temp.push_back(indent() + anonFuncEnd()); | ||
11323 | popAnonVarArg(); | ||
11324 | popFunctionScope(); | ||
11325 | out.push_back(join(temp)); | ||
11326 | } | ||
11327 | |||
10470 | void transformRepeat(Repeat_t* repeat, str_list& out) { | 11328 | void transformRepeat(Repeat_t* repeat, str_list& out) { |
10471 | str_list temp; | 11329 | str_list temp; |
10472 | pushScope(); | 11330 | pushScope(); |
@@ -10500,10 +11358,26 @@ private: | |||
10500 | pushScope(); | 11358 | pushScope(); |
10501 | } | 11359 | } |
10502 | bool extraScope = false; | 11360 | bool extraScope = false; |
11361 | if (switchNode->assignment) { | ||
11362 | if (needScope) { | ||
11363 | extraScope = true; | ||
11364 | temp.push_back(indent() + "do"s + nll(x)); | ||
11365 | pushScope(); | ||
11366 | } | ||
11367 | auto asmt = x->new_ptr<ExpListAssign_t>(); | ||
11368 | auto expList = x->new_ptr<ExpList_t>(); | ||
11369 | expList->exprs.push_back(switchNode->target); | ||
11370 | if (switchNode->assignment->expList) { | ||
11371 | expList->exprs.dup(switchNode->assignment->expList->exprs); | ||
11372 | } | ||
11373 | asmt->expList.set(expList); | ||
11374 | asmt->action.set(switchNode->assignment->assign); | ||
11375 | transformAssignment(asmt, temp); | ||
11376 | } | ||
10503 | auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); | 11377 | auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); |
10504 | if (objVar.empty() || !isLocal(objVar)) { | 11378 | if (objVar.empty() || !isLocal(objVar)) { |
10505 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { | 11379 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { |
10506 | if (needScope) { | 11380 | if (needScope && !extraScope) { |
10507 | extraScope = true; | 11381 | extraScope = true; |
10508 | temp.push_back(indent() + "do"s + nll(x)); | 11382 | temp.push_back(indent() + "do"s + nll(x)); |
10509 | pushScope(); | 11383 | pushScope(); |
@@ -10561,8 +11435,9 @@ private: | |||
10561 | } | 11435 | } |
10562 | temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); | 11436 | temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); |
10563 | pushScope(); | 11437 | pushScope(); |
10564 | auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); | 11438 | auto chainValue = toAst<ChainValue_t>(objVar, branch); |
10565 | auto info = extractDestructureInfo(assignment, true, false); | 11439 | auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch); |
11440 | auto info = extractDestructureInfo(assignment, true, true); | ||
10566 | transformAssignment(assignment, temp, true); | 11441 | transformAssignment(assignment, temp, true); |
10567 | str_list conds; | 11442 | str_list conds; |
10568 | for (const auto& des : info.destructures) { | 11443 | for (const auto& des : info.destructures) { |
@@ -10572,8 +11447,31 @@ private: | |||
10572 | const auto& destruct = std::get<Destructure>(des); | 11447 | const auto& destruct = std::get<Destructure>(des); |
10573 | for (const auto& item : destruct.items) { | 11448 | for (const auto& item : destruct.items) { |
10574 | if (!item.defVal) { | 11449 | if (!item.defVal) { |
10575 | transformExp(item.target, conds, ExpUsage::Closure); | 11450 | if (!isAssignable(item.target)) { |
10576 | conds.back().append(" ~= nil"s); | 11451 | auto callable = chainValue->items.front(); |
11452 | auto chain = callable->new_ptr<ChainValue_t>(); | ||
11453 | chain->items.push_back(callable); | ||
11454 | chain->items.dup(item.structure->items); | ||
11455 | if (specialChainValue(chain) == ChainType::Common) { | ||
11456 | transformChainValue(chain, conds, ExpUsage::Closure); | ||
11457 | auto vStr = conds.back(); | ||
11458 | conds.pop_back(); | ||
11459 | transformExp(item.target, conds, ExpUsage::Closure); | ||
11460 | conds.back().append(" == "s); | ||
11461 | conds.back().append(vStr); | ||
11462 | } else { | ||
11463 | auto varName = getUnusedName("_val_"sv); | ||
11464 | auto vExp = toAst<Exp_t>(varName, chain); | ||
11465 | auto asmt = assignmentFrom(vExp, newExp(chain, chain), chain); | ||
11466 | transformAssignment(asmt, temp); | ||
11467 | transformExp(item.target, conds, ExpUsage::Closure); | ||
11468 | conds.back().append(" == "s); | ||
11469 | conds.back().append(varName); | ||
11470 | } | ||
11471 | } else { | ||
11472 | transformExp(item.target, conds, ExpUsage::Closure); | ||
11473 | conds.back().append(" ~= nil"s); | ||
11474 | } | ||
10577 | } | 11475 | } |
10578 | } | 11476 | } |
10579 | } | 11477 | } |
@@ -10871,7 +11769,7 @@ private: | |||
10871 | } | 11769 | } |
10872 | transformAssignment(assignment, temp); | 11770 | transformAssignment(assignment, temp); |
10873 | for (const auto& name : vars) { | 11771 | for (const auto& name : vars) { |
10874 | markVarConst(name); | 11772 | markVarLocalConst(name); |
10875 | } | 11773 | } |
10876 | if (localAttrib->attrib.is<CloseAttrib_t>()) { | 11774 | if (localAttrib->attrib.is<CloseAttrib_t>()) { |
10877 | str_list leftVars, rightVars; | 11775 | str_list leftVars, rightVars; |
@@ -10943,7 +11841,7 @@ private: | |||
10943 | temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); | 11841 | temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); |
10944 | } | 11842 | } |
10945 | for (const auto& var : vars) { | 11843 | for (const auto& var : vars) { |
10946 | markVarConst(var); | 11844 | markVarLocalConst(var); |
10947 | } | 11845 | } |
10948 | } | 11846 | } |
10949 | if (!listB->exprs.empty()) { | 11847 | if (!listB->exprs.empty()) { |
@@ -10968,18 +11866,24 @@ private: | |||
10968 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); | 11866 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); |
10969 | transformAssignment(assignment, temp); | 11867 | transformAssignment(assignment, temp); |
10970 | for (const auto& name : vars) { | 11868 | for (const auto& name : vars) { |
10971 | markVarConst(name); | 11869 | markVarLocalConst(name); |
10972 | } | 11870 | } |
10973 | } | 11871 | } |
10974 | out.push_back(join(temp)); | 11872 | out.push_back(join(temp)); |
10975 | } | 11873 | } |
10976 | 11874 | ||
10977 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { | 11875 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { |
10978 | auto keyword = _parser.toString(breakLoop); | 11876 | auto isBreak = breakLoop->type.is<Break_t>(); |
11877 | auto keyword = isBreak ? "break"s : "continue"s; | ||
10979 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { | 11878 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { |
10980 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); | 11879 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); |
10981 | } | 11880 | } |
10982 | if (keyword == "break"sv) { | 11881 | if (isBreak) { |
11882 | if (breakLoop->value) { | ||
11883 | auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value); | ||
11884 | auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); | ||
11885 | transformAssignment(assignment, out); | ||
11886 | } | ||
10983 | out.push_back(indent() + keyword + nll(breakLoop)); | 11887 | out.push_back(indent() + keyword + nll(breakLoop)); |
10984 | return; | 11888 | return; |
10985 | } | 11889 | } |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index d352636..aff5978 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
@@ -31,6 +31,7 @@ struct YueConfig { | |||
31 | bool reserveLineNumber = true; | 31 | bool reserveLineNumber = true; |
32 | bool useSpaceOverTab = false; | 32 | bool useSpaceOverTab = false; |
33 | bool reserveComment = false; | 33 | bool reserveComment = false; |
34 | bool lax = false; | ||
34 | // internal options | 35 | // internal options |
35 | bool exporting = false; | 36 | bool exporting = false; |
36 | bool profiling = false; | 37 | bool profiling = false; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index ceb1f7c..1942e23 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -67,24 +67,28 @@ YueParser::YueParser() { | |||
67 | num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); | 67 | num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); |
68 | num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); | 68 | num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); |
69 | num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); | 69 | num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); |
70 | num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01"))); | ||
70 | Num = | 71 | Num = |
71 | "0x" >> ( | 72 | '0' >> ( |
72 | +num_lit >> ( | 73 | set("xX") >> ( |
73 | '.' >> +num_lit >> -num_expo_hex | | 74 | num_lit >> ( |
74 | num_expo_hex | | 75 | '.' >> num_lit >> -num_expo_hex | |
75 | lj_num | | 76 | num_expo_hex | |
76 | true_() | 77 | lj_num | |
77 | ) | ( | 78 | true_() |
78 | '.' >> +num_lit >> -num_expo_hex | 79 | ) | ( |
79 | ) | 80 | '.' >> num_lit >> -num_expo_hex |
81 | ) | ||
82 | ) | | ||
83 | set("bB") >> num_bin_lit | ||
80 | ) | | 84 | ) | |
81 | +num_char >> ( | 85 | num_char >> ( |
82 | '.' >> +num_char >> -num_expo | | 86 | '.' >> num_char >> -num_expo | |
83 | num_expo | | 87 | num_expo | |
84 | lj_num | | 88 | lj_num | |
85 | true_() | 89 | true_() |
86 | ) | | 90 | ) | |
87 | '.' >> +num_char >> -num_expo; | 91 | '.' >> num_char >> -num_expo; |
88 | 92 | ||
89 | cut = false_(); | 93 | cut = false_(); |
90 | Seperator = true_(); | 94 | Seperator = true_(); |
@@ -114,8 +118,8 @@ YueParser::YueParser() { | |||
114 | return false; | 118 | return false; |
115 | }); | 119 | }); |
116 | 120 | ||
117 | if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { | 121 | assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) { |
118 | throw ParserError("use := for if-assignment expression"sv, item.begin); | 122 | throw ParserError("use := for assignment expression"sv, item.begin); |
119 | return false; | 123 | return false; |
120 | }); | 124 | }); |
121 | 125 | ||
@@ -158,6 +162,13 @@ YueParser::YueParser() { | |||
158 | ) \ | 162 | ) \ |
159 | ) | 163 | ) |
160 | 164 | ||
165 | #define disable_until_rule(patt) ( \ | ||
166 | disable_until >> ( \ | ||
167 | (patt) >> enable_until | \ | ||
168 | enable_until >> cut \ | ||
169 | ) \ | ||
170 | ) | ||
171 | |||
161 | #define body_with(str) ( \ | 172 | #define body_with(str) ( \ |
162 | key(str) >> space >> (in_block | Statement) | \ | 173 | key(str) >> space >> (in_block | Statement) | \ |
163 | in_block | \ | 174 | in_block | \ |
@@ -321,7 +332,7 @@ YueParser::YueParser() { | |||
321 | Exp; | 332 | Exp; |
322 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); | 333 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); |
323 | import_tab_line = ( | 334 | import_tab_line = ( |
324 | push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) | 335 | push_indent_match >> ensure(space >> import_tab_list, pop_indent) |
325 | ) | space; | 336 | ) | space; |
326 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); | 337 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); |
327 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; | 338 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; |
@@ -338,7 +349,9 @@ YueParser::YueParser() { | |||
338 | 349 | ||
339 | ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); | 350 | ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); |
340 | 351 | ||
341 | Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; | 352 | ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> -(space >> key("as") >> space >> Variable); |
353 | |||
354 | Import = key("import") >> space >> (ImportAs | ImportFrom | ImportGlobal) | FromImport; | ||
342 | 355 | ||
343 | Label = "::" >> LabelName >> "::"; | 356 | Label = "::" >> LabelName >> "::"; |
344 | 357 | ||
@@ -346,11 +359,13 @@ YueParser::YueParser() { | |||
346 | 359 | ||
347 | ShortTabAppending = "[]" >> space >> Assign; | 360 | ShortTabAppending = "[]" >> space >> Assign; |
348 | 361 | ||
349 | BreakLoop = (expr("break") | "continue") >> not_alpha_num; | 362 | Break = key("break"); |
363 | Continue = key("continue"); | ||
364 | BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num; | ||
350 | 365 | ||
351 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); | 366 | Return = key("return") >> -(space >> (TableBlock | ExpListLow)); |
352 | 367 | ||
353 | with_exp = ExpList >> -(space >> Assign); | 368 | with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)); |
354 | 369 | ||
355 | With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); | 370 | With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); |
356 | SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); | 371 | SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); |
@@ -366,7 +381,8 @@ YueParser::YueParser() { | |||
366 | and_(SimpleTable | TableLit) >> Exp | | 381 | and_(SimpleTable | TableLit) >> Exp | |
367 | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) | 382 | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
368 | ); | 383 | ); |
369 | Switch = key("switch") >> space >> Exp >> | 384 | Switch = key("switch") >> space >> |
385 | Exp >> -(space >> Assignment) >> | ||
370 | space >> Seperator >> ( | 386 | space >> Seperator >> ( |
371 | SwitchCase >> space >> ( | 387 | SwitchCase >> space >> ( |
372 | switch_block | | 388 | switch_block | |
@@ -375,20 +391,26 @@ YueParser::YueParser() { | |||
375 | +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent | 391 | +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent |
376 | ); | 392 | ); |
377 | 393 | ||
378 | Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); | 394 | Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error); |
379 | IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); | 395 | IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); |
380 | if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); | 396 | if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); |
381 | if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; | 397 | if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; |
382 | IfType = (expr("if") | "unless") >> not_alpha_num; | 398 | IfType = (expr("if") | "unless") >> not_alpha_num; |
383 | If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; | 399 | If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; |
384 | 400 | ||
385 | WhileType = (expr("while") | "until") >> not_alpha_num; | 401 | WhileType = (expr("while") | pl::user("until", [](const item_t& item) { |
386 | While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); | 402 | State* st = reinterpret_cast<State*>(item.user_data); |
387 | Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; | 403 | return st->noUntilStack.empty() || !st->noUntilStack.back(); |
404 | })) >> not_alpha_num; | ||
405 | While = key(WhileType) >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); | ||
406 | Repeat = key("repeat") >> space >> ( | ||
407 | in_block >> line_break >> *space_break >> check_indent_match | | ||
408 | disable_until_rule(Statement) | ||
409 | ) >> space >> key("until") >> space >> Exp; | ||
388 | 410 | ||
389 | for_key = pl::user(key("for"), [](const item_t& item) { | 411 | for_key = pl::user(key("for"), [](const item_t& item) { |
390 | State* st = reinterpret_cast<State*>(item.user_data); | 412 | State* st = reinterpret_cast<State*>(item.user_data); |
391 | return st->noForStack.empty() || !st->noForStack.top(); | 413 | return st->noForStack.empty() || !st->noForStack.back(); |
392 | }); | 414 | }); |
393 | ForStepValue = ',' >> space >> Exp; | 415 | ForStepValue = ',' >> space >> Exp; |
394 | for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; | 416 | for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; |
@@ -402,18 +424,18 @@ YueParser::YueParser() { | |||
402 | 424 | ||
403 | Do = pl::user(key("do"), [](const item_t& item) { | 425 | Do = pl::user(key("do"), [](const item_t& item) { |
404 | State* st = reinterpret_cast<State*>(item.user_data); | 426 | State* st = reinterpret_cast<State*>(item.user_data); |
405 | return st->noDoStack.empty() || !st->noDoStack.top(); | 427 | return st->noDoStack.empty() || !st->noDoStack.back(); |
406 | }) >> space >> Body; | 428 | }) >> space >> Body; |
407 | 429 | ||
408 | disable_do = pl::user(true_(), [](const item_t& item) { | 430 | disable_do = pl::user(true_(), [](const item_t& item) { |
409 | State* st = reinterpret_cast<State*>(item.user_data); | 431 | State* st = reinterpret_cast<State*>(item.user_data); |
410 | st->noDoStack.push(true); | 432 | st->noDoStack.push_back(true); |
411 | return true; | 433 | return true; |
412 | }); | 434 | }); |
413 | 435 | ||
414 | enable_do = pl::user(true_(), [](const item_t& item) { | 436 | enable_do = pl::user(true_(), [](const item_t& item) { |
415 | State* st = reinterpret_cast<State*>(item.user_data); | 437 | State* st = reinterpret_cast<State*>(item.user_data); |
416 | st->noDoStack.pop(); | 438 | st->noDoStack.pop_back(); |
417 | return true; | 439 | return true; |
418 | }); | 440 | }); |
419 | 441 | ||
@@ -431,46 +453,58 @@ YueParser::YueParser() { | |||
431 | 453 | ||
432 | disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { | 454 | disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { |
433 | State* st = reinterpret_cast<State*>(item.user_data); | 455 | State* st = reinterpret_cast<State*>(item.user_data); |
434 | st->noDoStack.push(true); | 456 | st->noDoStack.push_back(true); |
435 | st->noChainBlockStack.push(true); | 457 | st->noChainBlockStack.push_back(true); |
436 | st->noTableBlockStack.push(true); | 458 | st->noTableBlockStack.push_back(true); |
437 | return true; | 459 | return true; |
438 | }); | 460 | }); |
439 | 461 | ||
440 | enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { | 462 | enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { |
441 | State* st = reinterpret_cast<State*>(item.user_data); | 463 | State* st = reinterpret_cast<State*>(item.user_data); |
442 | st->noDoStack.pop(); | 464 | st->noDoStack.pop_back(); |
443 | st->noChainBlockStack.pop(); | 465 | st->noChainBlockStack.pop_back(); |
444 | st->noTableBlockStack.pop(); | 466 | st->noTableBlockStack.pop_back(); |
445 | return true; | 467 | return true; |
446 | }); | 468 | }); |
447 | 469 | ||
448 | disable_arg_table_block = pl::user(true_(), [](const item_t& item) { | 470 | disable_arg_table_block = pl::user(true_(), [](const item_t& item) { |
449 | State* st = reinterpret_cast<State*>(item.user_data); | 471 | State* st = reinterpret_cast<State*>(item.user_data); |
450 | st->noTableBlockStack.push(true); | 472 | st->noTableBlockStack.push_back(true); |
451 | return true; | 473 | return true; |
452 | }); | 474 | }); |
453 | 475 | ||
454 | enable_arg_table_block = pl::user(true_(), [](const item_t& item) { | 476 | enable_arg_table_block = pl::user(true_(), [](const item_t& item) { |
455 | State* st = reinterpret_cast<State*>(item.user_data); | 477 | State* st = reinterpret_cast<State*>(item.user_data); |
456 | st->noTableBlockStack.pop(); | 478 | st->noTableBlockStack.pop_back(); |
457 | return true; | 479 | return true; |
458 | }); | 480 | }); |
459 | 481 | ||
460 | disable_for = pl::user(true_(), [](const item_t& item) { | 482 | disable_for = pl::user(true_(), [](const item_t& item) { |
461 | State* st = reinterpret_cast<State*>(item.user_data); | 483 | State* st = reinterpret_cast<State*>(item.user_data); |
462 | st->noForStack.push(true); | 484 | st->noForStack.push_back(true); |
463 | return true; | 485 | return true; |
464 | }); | 486 | }); |
465 | 487 | ||
466 | enable_for = pl::user(true_(), [](const item_t& item) { | 488 | enable_for = pl::user(true_(), [](const item_t& item) { |
467 | State* st = reinterpret_cast<State*>(item.user_data); | 489 | State* st = reinterpret_cast<State*>(item.user_data); |
468 | st->noForStack.pop(); | 490 | st->noForStack.pop_back(); |
491 | return true; | ||
492 | }); | ||
493 | |||
494 | disable_until = pl::user(true_(), [](const item_t& item) { | ||
495 | State* st = reinterpret_cast<State*>(item.user_data); | ||
496 | st->noUntilStack.push_back(true); | ||
497 | return true; | ||
498 | }); | ||
499 | |||
500 | enable_until = pl::user(true_(), [](const item_t& item) { | ||
501 | State* st = reinterpret_cast<State*>(item.user_data); | ||
502 | st->noUntilStack.pop_back(); | ||
469 | return true; | 503 | return true; |
470 | }); | 504 | }); |
471 | 505 | ||
472 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; | 506 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; |
473 | Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; | 507 | Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp) >> -CatchBlock; |
474 | 508 | ||
475 | list_value = | 509 | list_value = |
476 | and_( | 510 | and_( |
@@ -557,20 +591,20 @@ YueParser::YueParser() { | |||
557 | 591 | ||
558 | disable_chain = pl::user(true_(), [](const item_t& item) { | 592 | disable_chain = pl::user(true_(), [](const item_t& item) { |
559 | State* st = reinterpret_cast<State*>(item.user_data); | 593 | State* st = reinterpret_cast<State*>(item.user_data); |
560 | st->noChainBlockStack.push(true); | 594 | st->noChainBlockStack.push_back(true); |
561 | return true; | 595 | return true; |
562 | }); | 596 | }); |
563 | 597 | ||
564 | enable_chain = pl::user(true_(), [](const item_t& item) { | 598 | enable_chain = pl::user(true_(), [](const item_t& item) { |
565 | State* st = reinterpret_cast<State*>(item.user_data); | 599 | State* st = reinterpret_cast<State*>(item.user_data); |
566 | st->noChainBlockStack.pop(); | 600 | st->noChainBlockStack.pop_back(); |
567 | return true; | 601 | return true; |
568 | }); | 602 | }); |
569 | 603 | ||
570 | chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; | 604 | chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; |
571 | chain_block = pl::user(true_(), [](const item_t& item) { | 605 | chain_block = pl::user(true_(), [](const item_t& item) { |
572 | State* st = reinterpret_cast<State*>(item.user_data); | 606 | State* st = reinterpret_cast<State*>(item.user_data); |
573 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); | 607 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.back(); |
574 | }) >> +space_break >> advance_match >> ensure( | 608 | }) >> +space_break >> advance_match >> ensure( |
575 | chain_line >> *(+space_break >> chain_line), pop_indent); | 609 | chain_line >> *(+space_break >> chain_line), pop_indent); |
576 | ChainValue = | 610 | ChainValue = |
@@ -607,7 +641,15 @@ YueParser::YueParser() { | |||
607 | DoubleStringInner = +(not_("#{") >> double_string_plain); | 641 | DoubleStringInner = +(not_("#{") >> double_string_plain); |
608 | DoubleStringContent = DoubleStringInner | interp; | 642 | DoubleStringContent = DoubleStringInner | interp; |
609 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; | 643 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; |
610 | String = DoubleString | SingleString | LuaString; | 644 | |
645 | YAMLIndent = +set(" \t"); | ||
646 | YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char); | ||
647 | YAMLLineContent = YAMLLineInner | interp; | ||
648 | YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) | | ||
649 | advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent); | ||
650 | YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent); | ||
651 | |||
652 | String = DoubleString | SingleString | LuaString | YAMLMultiline; | ||
611 | 653 | ||
612 | lua_string_open = '[' >> *expr('=') >> '['; | 654 | lua_string_open = '[' >> *expr('=') >> '['; |
613 | lua_string_close = ']' >> *expr('=') >> ']'; | 655 | lua_string_close = ']' >> *expr('=') >> ']'; |
@@ -635,7 +677,7 @@ YueParser::YueParser() { | |||
635 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); | 677 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); |
636 | 678 | ||
637 | fn_args_lit_line = ( | 679 | fn_args_lit_line = ( |
638 | push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) | 680 | push_indent_match >> ensure(space >> fn_args_value_list, pop_indent) |
639 | ) | ( | 681 | ) | ( |
640 | space | 682 | space |
641 | ); | 683 | ); |
@@ -677,7 +719,8 @@ YueParser::YueParser() { | |||
677 | chain_with_colon = +chain_item >> -colon_chain; | 719 | chain_with_colon = +chain_item >> -colon_chain; |
678 | chain_items = chain_with_colon | colon_chain; | 720 | chain_items = chain_with_colon | colon_chain; |
679 | 721 | ||
680 | index = '[' >> not_('[') >> space >> Exp >> space >> ']'; | 722 | index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']'; |
723 | ReversedIndex = '#' >> space >> -('-' >> space >> Exp); | ||
681 | chain_item = | 724 | chain_item = |
682 | Invoke >> -ExistentialOp | | 725 | Invoke >> -ExistentialOp | |
683 | DotChainItem >> -ExistentialOp | | 726 | DotChainItem >> -ExistentialOp | |
@@ -734,7 +777,7 @@ YueParser::YueParser() { | |||
734 | 777 | ||
735 | table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); | 778 | table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); |
736 | TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); | 779 | TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); |
737 | TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( | 780 | TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule( |
738 | space >> key_value_list >> -(space >> ',') >> | 781 | space >> key_value_list >> -(space >> ',') >> |
739 | -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); | 782 | -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); |
740 | 783 | ||
@@ -755,7 +798,7 @@ YueParser::YueParser() { | |||
755 | 798 | ||
756 | GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); | 799 | GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); |
757 | GlobalOp = expr('*') | '^'; | 800 | GlobalOp = expr('*') | '^'; |
758 | Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); | 801 | Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues); |
759 | 802 | ||
760 | ExportDefault = key("default"); | 803 | ExportDefault = key("default"); |
761 | 804 | ||
@@ -837,24 +880,24 @@ YueParser::YueParser() { | |||
837 | key_value_line = check_indent_match >> space >> ( | 880 | key_value_line = check_indent_match >> space >> ( |
838 | key_value_list >> -(space >> ',') | | 881 | key_value_list >> -(space >> ',') | |
839 | TableBlockIndent | | 882 | TableBlockIndent | |
840 | '*' >> space >> (SpreadExp | Exp | TableBlock) | 883 | ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock) |
841 | ); | 884 | ); |
842 | 885 | ||
843 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); | 886 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); |
844 | 887 | ||
845 | fn_arg_def_lit_line = ( | 888 | fn_arg_def_lit_line = ( |
846 | push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) | 889 | push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent) |
847 | ) | ( | 890 | ) | ( |
848 | space | 891 | space |
849 | ); | 892 | ); |
850 | 893 | ||
851 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); | 894 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); |
852 | 895 | ||
853 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); | 896 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp); |
854 | 897 | ||
855 | FnArgDefList = Seperator >> ( | 898 | FnArgDefList = Seperator >> ( |
856 | fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | | 899 | fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) | |
857 | white >> VarArg | 900 | white >> VarArg >> -(space >> '`' >> space >> Name) |
858 | ); | 901 | ); |
859 | 902 | ||
860 | OuterVarShadow = key("using") >> space >> (NameList | key("nil")); | 903 | OuterVarShadow = key("using") >> space >> (NameList | key("nil")); |
@@ -883,6 +926,7 @@ YueParser::YueParser() { | |||
883 | 926 | ||
884 | FnArrowBack = '<' >> set("-="); | 927 | FnArrowBack = '<' >> set("-="); |
885 | Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; | 928 | Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; |
929 | SubBackcall = FnArrowBack >> space >> ChainValue; | ||
886 | 930 | ||
887 | PipeBody = Seperator >> | 931 | PipeBody = Seperator >> |
888 | pipe_operator >> space >> UnaryExp >> | 932 | pipe_operator >> space >> UnaryExp >> |
@@ -896,7 +940,7 @@ YueParser::YueParser() { | |||
896 | 940 | ||
897 | arg_table_block = pl::user(true_(), [](const item_t& item) { | 941 | arg_table_block = pl::user(true_(), [](const item_t& item) { |
898 | State* st = reinterpret_cast<State*>(item.user_data); | 942 | State* st = reinterpret_cast<State*>(item.user_data); |
899 | return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); | 943 | return st->noTableBlockStack.empty() || !st->noTableBlockStack.back(); |
900 | }) >> TableBlock; | 944 | }) >> TableBlock; |
901 | 945 | ||
902 | invoke_args_with_table = | 946 | invoke_args_with_table = |
@@ -936,11 +980,11 @@ YueParser::YueParser() { | |||
936 | 980 | ||
937 | SimpleValue = | 981 | SimpleValue = |
938 | TableLit | ConstValue | If | Switch | Try | With | | 982 | TableLit | ConstValue | If | Switch | Try | With | |
939 | ClassDecl | ForEach | For | While | Do | | 983 | ClassDecl | ForEach | For | While | Repeat | Do | |
940 | UnaryValue | TblComprehension | Comprehension | | 984 | UnaryValue | TblComprehension | Comprehension | |
941 | FunLit | Num | VarArg; | 985 | FunLit | Num | VarArg; |
942 | 986 | ||
943 | ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); | 987 | ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '='); |
944 | 988 | ||
945 | IfLine = IfType >> space >> IfCond; | 989 | IfLine = IfType >> space >> IfCond; |
946 | WhileLine = WhileType >> space >> Exp; | 990 | WhileLine = WhileType >> space >> Exp; |
@@ -997,11 +1041,16 @@ YueParser::YueParser() { | |||
997 | empty_line_break | | 1041 | empty_line_break | |
998 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) | 1042 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) |
999 | ); | 1043 | ); |
1000 | Block = Seperator >> line >> *(+line_break >> line); | 1044 | Block = Seperator >> (pl::user(true_(), [](const item_t& item) { |
1045 | State* st = reinterpret_cast<State*>(item.user_data); | ||
1046 | return st->lax; | ||
1047 | }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line)); | ||
1001 | 1048 | ||
1002 | shebang = "#!" >> *(not_(stop) >> any_char); | 1049 | shebang = "#!" >> *(not_(stop) >> any_char); |
1003 | BlockEnd = Block >> white >> stop; | 1050 | BlockEnd = Block >> white >> stop; |
1004 | File = -shebang >> -Block >> white >> stop; | 1051 | File = -shebang >> -Block >> white >> stop; |
1052 | |||
1053 | lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any()); | ||
1005 | } | 1054 | } |
1006 | // clang-format on | 1055 | // clang-format on |
1007 | 1056 | ||
@@ -1031,7 +1080,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) { | |||
1031 | return true; | 1080 | return true; |
1032 | } | 1081 | } |
1033 | 1082 | ||
1034 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { | 1083 | ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) { |
1035 | ParseInfo res; | 1084 | ParseInfo res; |
1036 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { | 1085 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { |
1037 | codes = codes.substr(3); | 1086 | codes = codes.substr(3); |
@@ -1049,6 +1098,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
1049 | error_list errors; | 1098 | error_list errors; |
1050 | try { | 1099 | try { |
1051 | State state; | 1100 | State state; |
1101 | state.lax = lax; | ||
1052 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); | 1102 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); |
1053 | if (state.exportCount > 0) { | 1103 | if (state.exportCount > 0) { |
1054 | int index = 0; | 1104 | int index = 0; |
@@ -1086,19 +1136,21 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
1086 | return res; | 1136 | return res; |
1087 | } | 1137 | } |
1088 | 1138 | ||
1089 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { | 1139 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) { |
1090 | auto it = _rules.find(astName); | 1140 | auto it = _rules.find(astName); |
1091 | if (it != _rules.end()) { | 1141 | if (it != _rules.end()) { |
1092 | return parse(codes, *it->second); | 1142 | return parse(codes, *it->second, lax); |
1093 | } | 1143 | } |
1094 | return {}; | 1144 | ParseInfo info{}; |
1145 | info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1}; | ||
1146 | return info; | ||
1095 | } | 1147 | } |
1096 | 1148 | ||
1097 | bool YueParser::match(std::string_view astName, std::string_view codes) { | 1149 | bool YueParser::match(std::string_view astName, std::string_view codes) { |
1098 | auto it = _rules.find(astName); | 1150 | auto it = _rules.find(astName); |
1099 | if (it != _rules.end()) { | 1151 | if (it != _rules.end()) { |
1100 | auto rEnd = rule(*it->second >> eof()); | 1152 | auto rEnd = rule(*it->second >> eof()); |
1101 | return parse(codes, rEnd).node; | 1153 | return parse(codes, rEnd, false).node; |
1102 | } | 1154 | } |
1103 | return false; | 1155 | return false; |
1104 | } | 1156 | } |
@@ -1134,6 +1186,24 @@ void trim(std::string& str) { | |||
1134 | str.erase(0, str.find_first_not_of(" \t\r\n")); | 1186 | str.erase(0, str.find_first_not_of(" \t\r\n")); |
1135 | str.erase(str.find_last_not_of(" \t\r\n") + 1); | 1187 | str.erase(str.find_last_not_of(" \t\r\n") + 1); |
1136 | } | 1188 | } |
1189 | |||
1190 | std::string toLuaDoubleString(const std::string& input) { | ||
1191 | std::string luaStr = "\""; | ||
1192 | for (char c : input) { | ||
1193 | switch (c) { | ||
1194 | case '\"': luaStr += "\\\""; break; | ||
1195 | case '\\': luaStr += "\\\\"; break; | ||
1196 | case '\n': luaStr += "\\n"; break; | ||
1197 | case '\r': luaStr += "\\r"; break; | ||
1198 | case '\t': luaStr += "\\t"; break; | ||
1199 | default: | ||
1200 | luaStr += c; | ||
1201 | break; | ||
1202 | } | ||
1203 | } | ||
1204 | luaStr += "\""; | ||
1205 | return luaStr; | ||
1206 | } | ||
1137 | } // namespace Utils | 1207 | } // namespace Utils |
1138 | 1208 | ||
1139 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { | 1209 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 02292e1..c91e530 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -74,16 +74,16 @@ extern std::unordered_set<std::string> Keywords; | |||
74 | class YueParser { | 74 | class YueParser { |
75 | public: | 75 | public: |
76 | template <class AST> | 76 | template <class AST> |
77 | ParseInfo parse(std::string_view codes) { | 77 | ParseInfo parse(std::string_view codes, bool lax) { |
78 | return parse(codes, getRule<AST>()); | 78 | return parse(codes, getRule<AST>(), lax); |
79 | } | 79 | } |
80 | 80 | ||
81 | ParseInfo parse(std::string_view astName, std::string_view codes); | 81 | ParseInfo parse(std::string_view astName, std::string_view codes, bool lax); |
82 | 82 | ||
83 | template <class AST> | 83 | template <class AST> |
84 | bool match(std::string_view codes) { | 84 | bool match(std::string_view codes) { |
85 | auto rEnd = rule(getRule<AST>() >> eof()); | 85 | auto rEnd = rule(getRule<AST>() >> eof()); |
86 | return parse(codes, rEnd).node; | 86 | return parse(codes, rEnd, false).node; |
87 | } | 87 | } |
88 | 88 | ||
89 | bool match(std::string_view astName, std::string_view codes); | 89 | bool match(std::string_view astName, std::string_view codes); |
@@ -102,13 +102,14 @@ public: | |||
102 | 102 | ||
103 | protected: | 103 | protected: |
104 | YueParser(); | 104 | YueParser(); |
105 | ParseInfo parse(std::string_view codes, rule& r); | 105 | ParseInfo parse(std::string_view codes, rule& r, bool lax); |
106 | bool startWith(std::string_view codes, rule& r); | 106 | bool startWith(std::string_view codes, rule& r); |
107 | 107 | ||
108 | struct State { | 108 | struct State { |
109 | State() { | 109 | State() { |
110 | indents.push(0); | 110 | indents.push(0); |
111 | } | 111 | } |
112 | bool lax = false; | ||
112 | bool exportDefault = false; | 113 | bool exportDefault = false; |
113 | bool exportMacro = false; | 114 | bool exportMacro = false; |
114 | bool exportMetatable = false; | 115 | bool exportMetatable = false; |
@@ -119,10 +120,11 @@ protected: | |||
119 | size_t stringOpen = 0; | 120 | size_t stringOpen = 0; |
120 | std::string buffer; | 121 | std::string buffer; |
121 | std::stack<int> indents; | 122 | std::stack<int> indents; |
122 | std::stack<bool> noDoStack; | 123 | std::vector<bool> noDoStack; |
123 | std::stack<bool> noChainBlockStack; | 124 | std::vector<bool> noChainBlockStack; |
124 | std::stack<bool> noTableBlockStack; | 125 | std::vector<bool> noTableBlockStack; |
125 | std::stack<bool> noForStack; | 126 | std::vector<bool> noForStack; |
127 | std::vector<bool> noUntilStack; | ||
126 | std::unordered_set<std::string> usedNames; | 128 | std::unordered_set<std::string> usedNames; |
127 | }; | 129 | }; |
128 | 130 | ||
@@ -156,7 +158,7 @@ private: | |||
156 | NONE_AST_RULE(invalid_interpolation_error); | 158 | NONE_AST_RULE(invalid_interpolation_error); |
157 | NONE_AST_RULE(confusing_unary_not_error); | 159 | NONE_AST_RULE(confusing_unary_not_error); |
158 | NONE_AST_RULE(table_key_pair_error); | 160 | NONE_AST_RULE(table_key_pair_error); |
159 | NONE_AST_RULE(if_assignment_syntax_error); | 161 | NONE_AST_RULE(assignment_expression_syntax_error); |
160 | 162 | ||
161 | NONE_AST_RULE(inc_exp_level); | 163 | NONE_AST_RULE(inc_exp_level); |
162 | NONE_AST_RULE(dec_exp_level); | 164 | NONE_AST_RULE(dec_exp_level); |
@@ -164,6 +166,7 @@ private: | |||
164 | NONE_AST_RULE(num_char); | 166 | NONE_AST_RULE(num_char); |
165 | NONE_AST_RULE(num_char_hex); | 167 | NONE_AST_RULE(num_char_hex); |
166 | NONE_AST_RULE(num_lit); | 168 | NONE_AST_RULE(num_lit); |
169 | NONE_AST_RULE(num_bin_lit); | ||
167 | NONE_AST_RULE(num_expo); | 170 | NONE_AST_RULE(num_expo); |
168 | NONE_AST_RULE(num_expo_hex); | 171 | NONE_AST_RULE(num_expo_hex); |
169 | NONE_AST_RULE(lj_num); | 172 | NONE_AST_RULE(lj_num); |
@@ -216,6 +219,8 @@ private: | |||
216 | NONE_AST_RULE(enable_for); | 219 | NONE_AST_RULE(enable_for); |
217 | NONE_AST_RULE(enable_fun_lit); | 220 | NONE_AST_RULE(enable_fun_lit); |
218 | NONE_AST_RULE(disable_fun_lit); | 221 | NONE_AST_RULE(disable_fun_lit); |
222 | NONE_AST_RULE(disable_until); | ||
223 | NONE_AST_RULE(enable_until); | ||
219 | NONE_AST_RULE(switch_else); | 224 | NONE_AST_RULE(switch_else); |
220 | NONE_AST_RULE(switch_block); | 225 | NONE_AST_RULE(switch_block); |
221 | NONE_AST_RULE(if_else_if); | 226 | NONE_AST_RULE(if_else_if); |
@@ -283,6 +288,7 @@ private: | |||
283 | NONE_AST_RULE(yue_line_comment); | 288 | NONE_AST_RULE(yue_line_comment); |
284 | NONE_AST_RULE(line); | 289 | NONE_AST_RULE(line); |
285 | NONE_AST_RULE(shebang); | 290 | NONE_AST_RULE(shebang); |
291 | NONE_AST_RULE(lax_line); | ||
286 | 292 | ||
287 | AST_RULE(Num); | 293 | AST_RULE(Num); |
288 | AST_RULE(Name); | 294 | AST_RULE(Name); |
@@ -314,12 +320,14 @@ private: | |||
314 | AST_RULE(ImportAllMacro); | 320 | AST_RULE(ImportAllMacro); |
315 | AST_RULE(ImportTabLit); | 321 | AST_RULE(ImportTabLit); |
316 | AST_RULE(ImportAs); | 322 | AST_RULE(ImportAs); |
323 | AST_RULE(ImportGlobal); | ||
317 | AST_RULE(Import); | 324 | AST_RULE(Import); |
318 | AST_RULE(Label); | 325 | AST_RULE(Label); |
319 | AST_RULE(Goto); | 326 | AST_RULE(Goto); |
320 | AST_RULE(ShortTabAppending); | 327 | AST_RULE(ShortTabAppending); |
321 | AST_RULE(FnArrowBack); | 328 | AST_RULE(FnArrowBack); |
322 | AST_RULE(Backcall); | 329 | AST_RULE(Backcall); |
330 | AST_RULE(SubBackcall); | ||
323 | AST_RULE(PipeBody); | 331 | AST_RULE(PipeBody); |
324 | AST_RULE(ExpListLow); | 332 | AST_RULE(ExpListLow); |
325 | AST_RULE(ExpList); | 333 | AST_RULE(ExpList); |
@@ -358,6 +366,7 @@ private: | |||
358 | AST_RULE(ExpOpValue); | 366 | AST_RULE(ExpOpValue); |
359 | AST_RULE(Exp); | 367 | AST_RULE(Exp); |
360 | AST_RULE(Callable); | 368 | AST_RULE(Callable); |
369 | AST_RULE(ReversedIndex); | ||
361 | AST_RULE(ChainValue); | 370 | AST_RULE(ChainValue); |
362 | AST_RULE(SimpleTable); | 371 | AST_RULE(SimpleTable); |
363 | AST_RULE(SimpleValue); | 372 | AST_RULE(SimpleValue); |
@@ -370,6 +379,11 @@ private: | |||
370 | AST_RULE(DoubleStringInner); | 379 | AST_RULE(DoubleStringInner); |
371 | AST_RULE(DoubleStringContent); | 380 | AST_RULE(DoubleStringContent); |
372 | AST_RULE(DoubleString); | 381 | AST_RULE(DoubleString); |
382 | AST_RULE(YAMLIndent); | ||
383 | AST_RULE(YAMLLineInner); | ||
384 | AST_RULE(YAMLLineContent); | ||
385 | AST_RULE(YAMLLine); | ||
386 | AST_RULE(YAMLMultiline); | ||
373 | AST_RULE(String); | 387 | AST_RULE(String); |
374 | AST_RULE(Parens); | 388 | AST_RULE(Parens); |
375 | AST_RULE(DotChainItem); | 389 | AST_RULE(DotChainItem); |
@@ -426,6 +440,8 @@ private: | |||
426 | AST_RULE(ExpListAssign); | 440 | AST_RULE(ExpListAssign); |
427 | AST_RULE(IfLine); | 441 | AST_RULE(IfLine); |
428 | AST_RULE(WhileLine); | 442 | AST_RULE(WhileLine); |
443 | AST_RULE(Break); | ||
444 | AST_RULE(Continue); | ||
429 | AST_RULE(BreakLoop); | 445 | AST_RULE(BreakLoop); |
430 | AST_RULE(StatementAppendix); | 446 | AST_RULE(StatementAppendix); |
431 | AST_RULE(Statement); | 447 | AST_RULE(Statement); |
@@ -443,6 +459,7 @@ private: | |||
443 | namespace Utils { | 459 | namespace Utils { |
444 | void replace(std::string& str, std::string_view from, std::string_view to); | 460 | void replace(std::string& str, std::string_view from, std::string_view to); |
445 | void trim(std::string& str); | 461 | void trim(std::string& str); |
462 | std::string toLuaDoubleString(const std::string& input); | ||
446 | } // namespace Utils | 463 | } // namespace Utils |
447 | 464 | ||
448 | } // namespace yue | 465 | } // namespace yue |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 7e8e8b7..61e3949 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
@@ -93,6 +93,12 @@ static void get_config(lua_State* L, yue::YueConfig& config) { | |||
93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; | 93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; |
94 | } | 94 | } |
95 | lua_pop(L, 1); | 95 | lua_pop(L, 1); |
96 | lua_pushliteral(L, "lax"); | ||
97 | lua_gettable(L, -2); | ||
98 | if (lua_isboolean(L, -1) != 0) { | ||
99 | config.lax = lua_toboolean(L, -1) != 0; | ||
100 | } | ||
101 | lua_pop(L, 1); | ||
96 | lua_pushliteral(L, "options"); | 102 | lua_pushliteral(L, "options"); |
97 | lua_gettable(L, -2); | 103 | lua_gettable(L, -2); |
98 | if (lua_istable(L, -1) != 0) { | 104 | if (lua_istable(L, -1) != 0) { |
@@ -180,7 +186,7 @@ static int yueformat(lua_State* L) { | |||
180 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); | 186 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); |
181 | } | 187 | } |
182 | std::string_view codes(input, len); | 188 | std::string_view codes(input, len); |
183 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes); | 189 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false); |
184 | if (info.error) { | 190 | if (info.error) { |
185 | const auto& error = info.error.value(); | 191 | const auto& error = info.error.value(); |
186 | if (!info.codes) { | 192 | if (!info.codes) { |
@@ -201,6 +207,7 @@ static int yueformat(lua_State* L) { | |||
201 | formatter.spaceOverTab = false; | 207 | formatter.spaceOverTab = false; |
202 | } | 208 | } |
203 | auto result = formatter.toString(info.node.get()); | 209 | auto result = formatter.toString(info.node.get()); |
210 | yue::Utils::replace(result, "\n\n", "\n"); | ||
204 | lua_pushlstring(L, result.c_str(), result.size()); | 211 | lua_pushlstring(L, result.c_str(), result.size()); |
205 | return 1; | 212 | return 1; |
206 | } | 213 | } |
@@ -282,8 +289,13 @@ static int yuetoast(lua_State* L) { | |||
282 | ruleName = {name, nameSize}; | 289 | ruleName = {name, nameSize}; |
283 | } | 290 | } |
284 | } | 291 | } |
292 | bool lax = false; | ||
293 | if (!lua_isnoneornil(L, 4)) { | ||
294 | luaL_checktype(L, 4, LUA_TBOOLEAN); | ||
295 | lax = lua_toboolean(L, 4) != 0; | ||
296 | } | ||
285 | auto& yueParser = yue::YueParser::shared(); | 297 | auto& yueParser = yue::YueParser::shared(); |
286 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); | 298 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax); |
287 | if (!info.error) { | 299 | if (!info.error) { |
288 | lua_createtable(L, 0, 0); | 300 | lua_createtable(L, 0, 0); |
289 | int tableIndex = lua_gettop(L); | 301 | int tableIndex = lua_gettop(L); |
diff --git a/win-build/Yuescript/Yuescript.vcxproj b/win-build/Yuescript/Yuescript.vcxproj index d073e70..87e13ce 100644 --- a/win-build/Yuescript/Yuescript.vcxproj +++ b/win-build/Yuescript/Yuescript.vcxproj | |||
@@ -215,6 +215,7 @@ | |||
215 | <Link> | 215 | <Link> |
216 | <SubSystem>Console</SubSystem> | 216 | <SubSystem>Console</SubSystem> |
217 | <GenerateDebugInformation>true</GenerateDebugInformation> | 217 | <GenerateDebugInformation>true</GenerateDebugInformation> |
218 | <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions> | ||
218 | </Link> | 219 | </Link> |
219 | </ItemDefinitionGroup> | 220 | </ItemDefinitionGroup> |
220 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug53|x64'"> | 221 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug53|x64'"> |
@@ -230,6 +231,7 @@ | |||
230 | <Link> | 231 | <Link> |
231 | <SubSystem>Console</SubSystem> | 232 | <SubSystem>Console</SubSystem> |
232 | <GenerateDebugInformation>true</GenerateDebugInformation> | 233 | <GenerateDebugInformation>true</GenerateDebugInformation> |
234 | <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions> | ||
233 | </Link> | 235 | </Link> |
234 | </ItemDefinitionGroup> | 236 | </ItemDefinitionGroup> |
235 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | 237 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
@@ -287,6 +289,7 @@ | |||
287 | <EnableCOMDATFolding>true</EnableCOMDATFolding> | 289 | <EnableCOMDATFolding>true</EnableCOMDATFolding> |
288 | <OptimizeReferences>true</OptimizeReferences> | 290 | <OptimizeReferences>true</OptimizeReferences> |
289 | <GenerateDebugInformation>true</GenerateDebugInformation> | 291 | <GenerateDebugInformation>true</GenerateDebugInformation> |
292 | <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions> | ||
290 | </Link> | 293 | </Link> |
291 | </ItemDefinitionGroup> | 294 | </ItemDefinitionGroup> |
292 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release53|x64'"> | 295 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release53|x64'"> |
@@ -306,6 +309,7 @@ | |||
306 | <EnableCOMDATFolding>true</EnableCOMDATFolding> | 309 | <EnableCOMDATFolding>true</EnableCOMDATFolding> |
307 | <OptimizeReferences>true</OptimizeReferences> | 310 | <OptimizeReferences>true</OptimizeReferences> |
308 | <GenerateDebugInformation>true</GenerateDebugInformation> | 311 | <GenerateDebugInformation>true</GenerateDebugInformation> |
312 | <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions> | ||
309 | </Link> | 313 | </Link> |
310 | </ItemDefinitionGroup> | 314 | </ItemDefinitionGroup> |
311 | <ItemGroup> | 315 | <ItemGroup> |