aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-07-18 11:51:39 +0800
committerLi Jin <dragon-fly@qq.com>2025-07-18 11:51:39 +0800
commit9d3d8ef2be15dfbf279de71241ff747a568e2c49 (patch)
tree53f88fa8a0e64dfa2262898312c9b4d988876fe8
parent51a74726e6f68851bafccba0fe69900274a81d59 (diff)
downloadyuescript-9d3d8ef2be15dfbf279de71241ff747a568e2c49.tar.gz
yuescript-9d3d8ef2be15dfbf279de71241ff747a568e2c49.tar.bz2
yuescript-9d3d8ef2be15dfbf279de71241ff747a568e2c49.zip
Added specs, tests and docs.
-rwxr-xr-xdoc/docs/doc/README.md107
-rwxr-xr-xdoc/docs/zh/doc/README.md107
-rw-r--r--spec/inputs/macro.yue54
-rw-r--r--spec/inputs/macro_export.yue31
-rw-r--r--spec/inputs/macro_teal.yue13
-rw-r--r--spec/inputs/macro_todo.yue7
-rw-r--r--spec/inputs/string.yue73
-rw-r--r--spec/outputs/macro.lua13
-rw-r--r--spec/outputs/string.lua41
-rw-r--r--src/yuescript/yue_compiler.cpp46
-rw-r--r--src/yuescript/yue_parser.cpp4
-rw-r--r--src/yuescript/yue_parser.h2
12 files changed, 435 insertions, 63 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index 7135a26..f0d67a5 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -444,6 +444,54 @@ print "Valid enum type:", $BodyType Static
444</pre> 444</pre>
445</YueDisplay> 445</YueDisplay>
446 446
447### Argument Validation
448
449You 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
452macro printNumAndStr = (num `Num, str `String) -> |
453 print(
454 #{num}
455 #{str}
456 )
457
458$printNumAndStr 123, "hello"
459```
460<YueDisplay>
461<pre>
462macro printNumAndStr = (num `Num, str `String) -> |
463 print(
464 #{num}
465 #{str}
466 )
467
468$printNumAndStr 123, "hello"
469</pre>
470</YueDisplay>
471
472If 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
475macro 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>
484macro 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
493For 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
447## Operator 495## Operator
448 496
449All 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. 497All 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.
@@ -1702,6 +1750,65 @@ binary = 0B10011
1702</pre> 1750</pre>
1703</YueDisplay> 1751</YueDisplay>
1704 1752
1753### YAML Multiline String
1754
1755The `|` prefix introduces a YAML-style multiline string literal:
1756
1757```moonscript
1758str = |
1759 key: value
1760 list:
1761 - item1
1762 - #{expr}
1763```
1764<YueDisplay>
1765<pre>
1766str = |
1767 key: value
1768 list:
1769 - item1
1770 - #{expr}
1771</pre>
1772</YueDisplay>
1773
1774This 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
1776YAML 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
1779fn = ->
1780 str = |
1781 foo:
1782 bar: baz
1783 return str
1784```
1785<YueDisplay>
1786<pre>
1787fn = ->
1788 str = |
1789 foo:
1790 bar: baz
1791 return str
1792</pre>
1793</YueDisplay>
1794
1795Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures.
1796
1797All 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
1800str = |
1801 path: "C:\Program Files\App"
1802 note: 'He said: "#{Hello}!"'
1803```
1804<YueDisplay>
1805<pre>
1806str = |
1807 path: "C:\Program Files\App"
1808 note: 'He said: "#{Hello}!"'
1809</pre>
1810</YueDisplay>
1811
1705## Function Literals 1812## Function Literals
1706 1813
1707All functions are created using a function expression. A simple function is denoted using the arrow: **->**. 1814All functions are created using a function expression. A simple function is denoted using the arrow: **->**.
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md
index 61b746c..15f4768 100755
--- a/doc/docs/zh/doc/README.md
+++ b/doc/docs/zh/doc/README.md
@@ -442,6 +442,54 @@ print "有效的枚举类型:", $BodyType Static
442</pre> 442</pre>
443</YueDisplay> 443</YueDisplay>
444 444
445### 宏参数检查
446
447可以直接在参数列表中声明期望的 AST 节点类型,并在编译时检查传入的宏参数是否符合预期。
448
449```moonscript
450macro printNumAndStr = (num `Num, str `String) -> |
451 print(
452 #{num}
453 #{str}
454 )
455
456$printNumAndStr 123, "hello"
457```
458<YueDisplay>
459<pre>
460macro 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
473macro 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>
482macro 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
445## 操作符 493## 操作符
446 494
447Lua的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\** 或 **::** 均可用于编写链式函数调用,如写作 `tb\func!` 或 `tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。 495Lua的所有二元和一元操作符在月之脚本中都是可用的。此外,**!=** 符号是 **~=** 的别名,而 **\\** 或 **::** 均可用于编写链式函数调用,如写作 `tb\func!` 或 `tb::func!`。此外月之脚本还提供了一些其他特殊的操作符,以编写更具表达力的代码。
@@ -1700,6 +1748,65 @@ binary = 0B10011
1700</pre> 1748</pre>
1701</YueDisplay> 1749</YueDisplay>
1702 1750
1751### YAML 风格字符串
1752
1753使用 `|` 前缀标记一个多行 YAML 风格字符串:
1754
1755```moonscript
1756str = |
1757 key: value
1758 list:
1759 - item1
1760 - #{expr}
1761```
1762<YueDisplay>
1763<pre>
1764str = |
1765 key: value
1766 list:
1767 - item1
1768 - #{expr}
1769</pre>
1770</YueDisplay>
1771
1772其效果类似于原生 Lua 的多行拼接,所有文本(含换行)将被保留下来,并支持 `#{...}` 语法,通过 `tostring(expr)` 插入表达式结果。
1773
1774YAML 风格的多行字符串会自动检测首行后最小的公共缩进,并从所有行中删除该前缀空白字符。这让你可以在代码中对齐文本,但输出字符串不会带多余缩进。
1775
1776```moonscript
1777fn = ->
1778 str = |
1779 foo:
1780 bar: baz
1781 return str
1782```
1783<YueDisplay>
1784<pre>
1785fn = ->
1786 str = |
1787 foo:
1788 bar: baz
1789 return str
1790</pre>
1791</YueDisplay>
1792
1793输出字符串中的 foo: 对齐到行首,不会带有函数缩进空格。保留内部缩进的相对结构,适合书写结构化嵌套样式的内容。
1794
1795支持自动处理字符中的引号、反斜杠等特殊符号,无需手动转义:
1796
1797```moonscript
1798str = |
1799 path: "C:\Program Files\App"
1800 note: 'He said: "#{Hello}!"'
1801```
1802<YueDisplay>
1803<pre>
1804str = |
1805 path: "C:\Program Files\App"
1806 note: 'He said: "#{Hello}!"'
1807</pre>
1808</YueDisplay>
1809
1703## 函数字面量 1810## 函数字面量
1704 1811
1705所有函数都是使用月之脚本的函数表达式创建的。一个简单的函数可以用箭头表示为:**->**。 1812所有函数都是使用月之脚本的函数表达式创建的。一个简单的函数可以用箭头表示为:**->**。
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
61print $NumAndStr 123, 'xyz' 61print $NumAndStr 123, 'xyz'
62 62
63macro NumAndStr2 = (num`Num, str`SingleString) -> |
64 [#{num}, #{str}]
65
66print $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
102macro reduce = (items, def, action)-> 107macro reduce = (items, def, action)->
103 $showMacro "reduce", "if ##{items} == 0 108 $showMacro "reduce", |
104 #{def} 109 if ##{items} == 0
105else 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
111macro foreach = (items, action)-> 117macro foreach = (items, action)->
112 $showMacro "foreach", "for _ in *#{items} 118 $showMacro "foreach", "for _ in *#{items}
@@ -154,13 +160,15 @@ macro curry = (...)->
154f = $curry x,y,z,do 160f = $curry x,y,z,do
155 print x,y,z 161 print x,y,z
156 162
157macro get_inner = (var)-> "do 163macro get_inner = (var)-> |
158 a = 1 164 do
159 a + 1" 165 a = 1
166 a + 1
160 167
161macro get_inner_hygienic = (var)-> "(-> 168macro get_inner_hygienic = (var)-> |
162 local a = 1 169 (->
163 a + 1)!" 170 local a = 1
171 a + 1)!
164 172
165do 173do
166 a = 8 174 a = 8
@@ -196,6 +204,18 @@ end
196 204
197print x 205print x
198 206
207import "yue"
208macro 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
199macro def = (fname, ...)-> 219macro 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
320macro tb = -> "{'abc', a:123, <call>:=> 998}" 340macro tb = -> |
341 {
342 'abc'
343 a: 123
344 <call>: => 998
345 }
346
321print $tb[1], $tb.a, ($tb)!, $tb! 347print $tb[1], $tb.a, ($tb)!, $tb!
322 348
323print "current line: #{ $LINE }" 349print "current line: #{ $LINE }"
diff --git a/spec/inputs/macro_export.yue b/spec/inputs/macro_export.yue
index 75fd813..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
10export macro showMacro = (name, res)-> 10export macro showMacro = (name, res)->
11 if debugMacro then " 11 if debugMacro then |
12do 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(
39do 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
47export macro enum = (...) -> 48export 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
7macro to_lua = (code)-> 7macro 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
10macro trim = (name)-> 12macro trim = (name)-> |
11 "if result := #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" 13 if result := #{name}\match '[\'"](.*)[\'"]'
14 result
15 else
16 #{name}
12 17
13export macro local = (decl, value = nil)-> 18export 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
8export macro todo = (msg)-> 8export 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/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"
74something"hello"\world! 74something"hello"\world!
75something "hello"\world! 75something "hello"\world!
76 76
77do
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 ) |> print
145
146export yaml = |
147 version: #{ver}
148 ok: true
149
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua
index 9f5507c..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})
29print({
30 456,
31 'abc'
32})
29do 33do
30 assert(item == nil) 34 assert(item == nil)
31end 35end
@@ -213,6 +217,13 @@ function tb:func()
213end 217end
214end 218end
215print(x) 219print(x)
220local yue = require("yue")
221do
222local function f2(a)
223 return a + 1
224end
225x = x + f2(3)
226end
216local sel 227local sel
217sel = function(a, b, c) 228sel = 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}))
320print("current line: " .. tostring(323)) 331print("current line: " .. tostring(349))
321do 332do
322 do 333 do
323-- TODO 334-- TODO
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 @@
1local _module_0 = { }
1local hi = "hello" 2local hi = "hello"
2local hello = "what the heckyes" 3local hello = "what the heckyes"
3print(hi) 4print(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)
43something("hello"):world() 44something("hello"):world()
44return something(("hello"):world()) 45something(("hello"):world())
46do
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"))
80end
81local yaml = "version: " .. tostring(ver) .. "\nok: true"
82_module_0["yaml"] = yaml
83return _module_0
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 3768fc9..a8d222d 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -5440,7 +5440,7 @@ private:
5440 if (def->defaultValue) { 5440 if (def->defaultValue) {
5441 defVal = _parser.toString(def->defaultValue); 5441 defVal = _parser.toString(def->defaultValue);
5442 Utils::trim(defVal); 5442 Utils::trim(defVal);
5443 defVal = '=' + Utils::toLuaString(defVal); 5443 defVal = '=' + Utils::toLuaDoubleString(defVal);
5444 } 5444 }
5445 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5445 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5446 } 5446 }
@@ -9185,15 +9185,34 @@ private:
9185 auto line = static_cast<YAMLLine_t*>(line_); 9185 auto line = static_cast<YAMLLine_t*>(line_);
9186 if (!line->segments.empty()) { 9186 if (!line->segments.empty()) {
9187 str_list segs; 9187 str_list segs;
9188 bool firstSeg = true;
9188 for (auto seg_ : line->segments.objects()) { 9189 for (auto seg_ : line->segments.objects()) {
9189 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get(); 9190 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9190 switch (content->get_id()) { 9191 switch (content->get_id()) {
9191 case id<YAMLLineInner_t>(): { 9192 case id<YAMLLineInner_t>(): {
9192 auto str = _parser.toString(content); 9193 auto seg = _parser.toString(content);
9193 Utils::replace(str, "\r\n"sv, "\n"sv); 9194 if (!indent) {
9194 Utils::replace(str, "\n"sv, "\\n"sv); 9195 auto pos = seg.find_first_not_of("\t "sv);
9195 Utils::replace(str, "\\#"sv, "#"sv); 9196 if (pos == std::string::npos) {
9196 segs.push_back('\"' + str + '\"'); 9197 indent = seg;
9198 firstSeg = false;
9199 continue;
9200 } else {
9201 indent = std::string{seg.c_str(), pos};
9202 }
9203 }
9204 if (firstSeg) {
9205 firstSeg = false;
9206 if (std::string_view{seg}.substr(0, indent.value().size()) != indent.value()) {
9207 throw CompileError("inconsistent indent"sv, line);
9208 }
9209 auto seqStr = seg.substr(indent.value().size());
9210 if (!seqStr.empty()) {
9211 segs.push_back(Utils::toLuaDoubleString(seqStr));
9212 }
9213 } else {
9214 segs.push_back(Utils::toLuaDoubleString(seg));
9215 }
9197 break; 9216 break;
9198 } 9217 }
9199 case id<Exp_t>(): { 9218 case id<Exp_t>(): {
@@ -9204,20 +9223,7 @@ private:
9204 default: YUEE("AST node mismatch", content); break; 9223 default: YUEE("AST node mismatch", content); break;
9205 } 9224 }
9206 } 9225 }
9207 auto lineStr = join(segs, " .. "sv); 9226 temp.push_back(join(segs, " .. "sv));
9208 if (!indent) {
9209 auto pos = lineStr.find_first_not_of("\t "sv, 1);
9210 if (pos == std::string::npos) {
9211 throw CompileError("expecting first line indent"sv, line);
9212 }
9213 indent = std::string{lineStr.c_str(), pos};
9214 } else {
9215 if (std::string_view{lineStr}.substr(0, indent.value().size()) != indent.value()) {
9216 throw CompileError("inconsistent indent"sv, line);
9217 }
9218 }
9219 lineStr = '"' + lineStr.substr(indent.value().size());
9220 temp.push_back(lineStr);
9221 } 9227 }
9222 } 9228 }
9223 auto str = join(temp, " .. '\\n' .. "sv); 9229 auto str = join(temp, " .. '\\n' .. "sv);
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index eebc676..2e21a52 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -645,7 +645,7 @@ YueParser::YueParser() {
645 YAMLLine = check_indent_match >> Seperator >> +YAMLLineContent | 645 YAMLLine = check_indent_match >> Seperator >> +YAMLLineContent |
646 advance_match >> Seperator >> ensure(+YAMLLineContent, pop_indent) | 646 advance_match >> Seperator >> ensure(+YAMLLineContent, pop_indent) |
647 Seperator >> *set(" \t") >> and_(line_break); 647 Seperator >> *set(" \t") >> and_(line_break);
648 YAMLMultiline = '|' >> Seperator >> +space_break >> advance_match >> ensure(YAMLLine >> *(*set(" \t") >> line_break >> YAMLLine), pop_indent); 648 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(*set(" \t") >> line_break >> YAMLLine), pop_indent);
649 649
650 String = DoubleString | SingleString | LuaString | YAMLMultiline; 650 String = DoubleString | SingleString | LuaString | YAMLMultiline;
651 651
@@ -1185,7 +1185,7 @@ void trim(std::string& str) {
1185 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1185 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1186} 1186}
1187 1187
1188std::string toLuaString(const std::string& input) { 1188std::string toLuaDoubleString(const std::string& input) {
1189 std::string luaStr = "\""; 1189 std::string luaStr = "\"";
1190 for (char c : input) { 1190 for (char c : input) {
1191 switch (c) { 1191 switch (c) {
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 15f9277..f4e0ab1 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -457,7 +457,7 @@ private:
457namespace Utils { 457namespace Utils {
458void replace(std::string& str, std::string_view from, std::string_view to); 458void replace(std::string& str, std::string_view from, std::string_view to);
459void trim(std::string& str); 459void trim(std::string& str);
460std::string toLuaString(const std::string& input); 460std::string toLuaDoubleString(const std::string& input);
461} // namespace Utils 461} // namespace Utils
462 462
463} // namespace yue 463} // namespace yue