diff options
Diffstat (limited to '')
| -rwxr-xr-x | src/yuescript/yue_ast.h | 5 | ||||
| -rwxr-xr-x | src/yuescript/yue_compiler.cpp | 193 | ||||
| -rwxr-xr-x | src/yuescript/yue_parser.cpp | 6 | ||||
| -rwxr-xr-x | src/yuescript/yue_parser.h | 1 |
4 files changed, 110 insertions, 95 deletions
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 7762c91..79e35a5 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -561,11 +561,14 @@ AST_END(Invoke) | |||
| 561 | AST_LEAF(existential_op) | 561 | AST_LEAF(existential_op) |
| 562 | AST_END(existential_op) | 562 | AST_END(existential_op) |
| 563 | 563 | ||
| 564 | AST_LEAF(table_appending_op) | ||
| 565 | AST_END(table_appending_op) | ||
| 566 | |||
| 564 | class InvokeArgs_t; | 567 | class InvokeArgs_t; |
| 565 | 568 | ||
| 566 | AST_NODE(ChainValue) | 569 | AST_NODE(ChainValue) |
| 567 | ast_ptr<true, Seperator_t> sep; | 570 | ast_ptr<true, Seperator_t> sep; |
| 568 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, existential_op_t> items; | 571 | ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, existential_op_t, table_appending_op_t> items; |
| 569 | AST_MEMBER(ChainValue, &sep, &items) | 572 | AST_MEMBER(ChainValue, &sep, &items) |
| 570 | AST_END(ChainValue) | 573 | AST_END(ChainValue) |
| 571 | 574 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 6617ec5..6bc9fe8 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -60,7 +60,7 @@ using namespace parserlib; | |||
| 60 | 60 | ||
| 61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
| 62 | 62 | ||
| 63 | const std::string_view version = "0.9.9"sv; | 63 | const std::string_view version = "0.9.10"sv; |
| 64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
| 65 | 65 | ||
| 66 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
| @@ -809,6 +809,7 @@ private: | |||
| 809 | switch (lastItem->getId()) { | 809 | switch (lastItem->getId()) { |
| 810 | case id<DotChainItem_t>(): | 810 | case id<DotChainItem_t>(): |
| 811 | case id<Exp_t>(): | 811 | case id<Exp_t>(): |
| 812 | case id<table_appending_op_t>(): | ||
| 812 | return true; | 813 | return true; |
| 813 | } | 814 | } |
| 814 | } | 815 | } |
| @@ -1212,25 +1213,52 @@ private: | |||
| 1212 | BREAK_IF(!value); | 1213 | BREAK_IF(!value); |
| 1213 | auto chainValue = value->item.as<ChainValue_t>(); | 1214 | auto chainValue = value->item.as<ChainValue_t>(); |
| 1214 | BREAK_IF(!chainValue); | 1215 | BREAK_IF(!chainValue); |
| 1215 | auto dot = ast_cast<DotChainItem_t>(chainValue->items.back()); | 1216 | str_list temp; |
| 1216 | BREAK_IF(!dot); | 1217 | if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { |
| 1217 | BREAK_IF(!dot->name.is<Metatable_t>()); | 1218 | BREAK_IF(!dot->name.is<Metatable_t>()); |
| 1218 | str_list args; | 1219 | str_list args; |
| 1219 | chainValue->items.pop_back(); | 1220 | chainValue->items.pop_back(); |
| 1220 | if (chainValue->items.empty()) { | 1221 | if (chainValue->items.empty()) { |
| 1221 | if (_withVars.empty()) { | 1222 | if (_withVars.empty()) { |
| 1222 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); | 1223 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); |
| 1224 | } else { | ||
| 1225 | args.push_back(_withVars.top()); | ||
| 1226 | } | ||
| 1223 | } else { | 1227 | } else { |
| 1224 | args.push_back(_withVars.top()); | 1228 | transformExp(static_cast<Exp_t*>(*it), args, ExpUsage::Closure); |
| 1225 | } | 1229 | } |
| 1226 | } else { | 1230 | if (vit != values.end()) transformAssignItem(*vit, args); |
| 1227 | transformExp(static_cast<Exp_t*>(*it), args, ExpUsage::Closure); | 1231 | else args.push_back("nil"s); |
| 1228 | } | 1232 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); |
| 1229 | if (vit != values.end()) transformAssignItem(*vit, args); | 1233 | temp.push_back(clearBuf()); |
| 1230 | else args.push_back("nil"s); | 1234 | } else if (ast_is<table_appending_op_t>(chainValue->items.back())) { |
| 1231 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); | 1235 | chainValue->items.pop_back(); |
| 1232 | str_list temp; | 1236 | auto varName = singleVariableFrom(chainValue); |
| 1233 | temp.push_back(clearBuf()); | 1237 | bool isScoped = false; |
| 1238 | if (varName.empty() || !isLocal(varName)) { | ||
| 1239 | isScoped = true; | ||
| 1240 | temp.push_back(indent() + "do"s + nll(x)); | ||
| 1241 | pushScope(); | ||
| 1242 | auto objVar = getUnusedName("_obj_"sv); | ||
| 1243 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 1244 | newAssignment->expList.set(toAst<ExpList_t>(objVar, x)); | ||
| 1245 | auto assign = x->new_ptr<Assign_t>(); | ||
| 1246 | assign->values.push_back(*it); | ||
| 1247 | newAssignment->action.set(assign); | ||
| 1248 | transformAssignment(newAssignment, temp); | ||
| 1249 | varName = objVar; | ||
| 1250 | } | ||
| 1251 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 1252 | newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); | ||
| 1253 | auto assign = x->new_ptr<Assign_t>(); | ||
| 1254 | assign->values.push_back(*vit); | ||
| 1255 | newAssignment->action.set(assign); | ||
| 1256 | transformAssignment(newAssignment, temp); | ||
| 1257 | if (isScoped) { | ||
| 1258 | popScope(); | ||
| 1259 | temp.push_back(indent() + "end"s + nlr(x)); | ||
| 1260 | } | ||
| 1261 | } else break; | ||
| 1234 | auto newExpList = x->new_ptr<ExpList_t>(); | 1262 | auto newExpList = x->new_ptr<ExpList_t>(); |
| 1235 | auto newAssign = x->new_ptr<Assign_t>(); | 1263 | auto newAssign = x->new_ptr<Assign_t>(); |
| 1236 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | 1264 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -1243,7 +1271,7 @@ private: | |||
| 1243 | if (value != *vit) newAssign->values.push_back(value); | 1271 | if (value != *vit) newAssign->values.push_back(value); |
| 1244 | } | 1272 | } |
| 1245 | if (newExpList->exprs.empty() && newAssign->values.empty()) { | 1273 | if (newExpList->exprs.empty() && newAssign->values.empty()) { |
| 1246 | out.push_back(temp.back()); | 1274 | out.push_back(join(temp)); |
| 1247 | return; | 1275 | return; |
| 1248 | } | 1276 | } |
| 1249 | if (newExpList->exprs.size() < newAssign->values.size()) { | 1277 | if (newExpList->exprs.size() < newAssign->values.size()) { |
| @@ -2016,81 +2044,67 @@ private: | |||
| 2016 | if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); | 2044 | if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); |
| 2017 | auto chain = leftValue->item.as<ChainValue_t>(); | 2045 | auto chain = leftValue->item.as<ChainValue_t>(); |
| 2018 | if (!chain) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, chain)); | 2046 | if (!chain) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, chain)); |
| 2019 | auto op = _parser.toString(update->op); | 2047 | BLOCK_START |
| 2020 | { | 2048 | { |
| 2021 | auto dot = ast_cast<DotChainItem_t>(chain->items.back()); | 2049 | auto dot = ast_cast<DotChainItem_t>(chain->items.back()); |
| 2022 | if (dot && dot->name.is<Metatable_t>()) { | 2050 | if (dot && dot->name.is<Metatable_t>()) { |
| 2023 | throw std::logic_error(_info.errorMessage("can not apply update to a metatable"sv, leftExp)); | 2051 | throw std::logic_error(_info.errorMessage("can not apply update to a metatable"sv, leftExp)); |
| 2024 | } | 2052 | } |
| 2025 | BLOCK_START | 2053 | BREAK_IF(chain->items.size() < 2); |
| 2026 | if (op == "#"sv) { | 2054 | if (chain->items.size() == 2) { |
| 2027 | auto varName = singleVariableFrom(chain); | 2055 | if (auto callable = ast_cast<Callable_t>(chain->items.front())) { |
| 2028 | BREAK_IF(!varName.empty() && isLocal(varName)); | 2056 | ast_node* var = callable->item.as<Variable_t>(); |
| 2029 | auto objVar = getUnusedName("_obj_"sv); | 2057 | if (auto self = callable->item.as<SelfName_t>()) { |
| 2030 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | 2058 | var = self->name.as<self_t>(); |
| 2031 | newAssignment->expList.set(toAst<ExpList_t>(objVar, x)); | ||
| 2032 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2033 | assign->values.push_back(leftExp); | ||
| 2034 | newAssignment->action.set(assign); | ||
| 2035 | transformAssignment(newAssignment, temp); | ||
| 2036 | chain->items.clear(); | ||
| 2037 | chain->items.push_back(toAst<Callable_t>(objVar, x)); | ||
| 2038 | } else { | ||
| 2039 | BREAK_IF(chain->items.size() < 2); | ||
| 2040 | if (chain->items.size() == 2) { | ||
| 2041 | if (auto callable = ast_cast<Callable_t>(chain->items.front())) { | ||
| 2042 | ast_node* var = callable->item.as<Variable_t>(); | ||
| 2043 | if (auto self = callable->item.as<SelfName_t>()) { | ||
| 2044 | var = self->name.as<self_t>(); | ||
| 2045 | } | ||
| 2046 | BREAK_IF(var && isLocal(_parser.toString(var))); | ||
| 2047 | } | 2059 | } |
| 2060 | BREAK_IF(var && isLocal(_parser.toString(var))); | ||
| 2048 | } | 2061 | } |
| 2049 | auto tmpChain = x->new_ptr<ChainValue_t>(); | ||
| 2050 | ast_ptr<false, ast_node> ptr(chain->items.back()); | ||
| 2051 | for (auto item : chain->items.objects()) { | ||
| 2052 | if (item != ptr) { | ||
| 2053 | tmpChain->items.push_back(item); | ||
| 2054 | } | ||
| 2055 | } | ||
| 2056 | auto value = x->new_ptr<Value_t>(); | ||
| 2057 | value->item.set(tmpChain); | ||
| 2058 | auto exp = newExp(value, x); | ||
| 2059 | auto objVar = getUnusedName("_obj_"sv); | ||
| 2060 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2061 | newAssignment->expList.set(toAst<ExpList_t>(objVar, x)); | ||
| 2062 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2063 | assign->values.push_back(exp); | ||
| 2064 | newAssignment->action.set(assign); | ||
| 2065 | transformAssignment(newAssignment, temp); | ||
| 2066 | chain->items.clear(); | ||
| 2067 | chain->items.push_back(toAst<Callable_t>(objVar, x)); | ||
| 2068 | chain->items.push_back(ptr); | ||
| 2069 | } | 2062 | } |
| 2070 | BLOCK_END | ||
| 2071 | auto tmpChain = x->new_ptr<ChainValue_t>(); | 2063 | auto tmpChain = x->new_ptr<ChainValue_t>(); |
| 2064 | ast_ptr<false, ast_node> ptr(chain->items.back()); | ||
| 2072 | for (auto item : chain->items.objects()) { | 2065 | for (auto item : chain->items.objects()) { |
| 2073 | bool itemAdded = false; | 2066 | if (item != ptr) { |
| 2074 | BLOCK_START | 2067 | tmpChain->items.push_back(item); |
| 2075 | auto exp = ast_cast<Exp_t>(item); | 2068 | } |
| 2076 | BREAK_IF(!exp); | ||
| 2077 | auto var = singleVariableFrom(exp); | ||
| 2078 | BREAK_IF(!var.empty()); | ||
| 2079 | auto upVar = getUnusedName("_update_"sv); | ||
| 2080 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2081 | newAssignment->expList.set(toAst<ExpList_t>(upVar, x)); | ||
| 2082 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2083 | assign->values.push_back(exp); | ||
| 2084 | newAssignment->action.set(assign); | ||
| 2085 | transformAssignment(newAssignment, temp); | ||
| 2086 | tmpChain->items.push_back(toAst<Exp_t>(upVar, x)); | ||
| 2087 | itemAdded = true; | ||
| 2088 | BLOCK_END | ||
| 2089 | if (!itemAdded) tmpChain->items.push_back(item); | ||
| 2090 | } | 2069 | } |
| 2070 | auto value = x->new_ptr<Value_t>(); | ||
| 2071 | value->item.set(tmpChain); | ||
| 2072 | auto exp = newExp(value, x); | ||
| 2073 | auto objVar = getUnusedName("_obj_"sv); | ||
| 2074 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2075 | newAssignment->expList.set(toAst<ExpList_t>(objVar, x)); | ||
| 2076 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2077 | assign->values.push_back(exp); | ||
| 2078 | newAssignment->action.set(assign); | ||
| 2079 | transformAssignment(newAssignment, temp); | ||
| 2091 | chain->items.clear(); | 2080 | chain->items.clear(); |
| 2092 | chain->items.dup(tmpChain->items); | 2081 | chain->items.push_back(toAst<Callable_t>(objVar, x)); |
| 2082 | chain->items.push_back(ptr); | ||
| 2093 | } | 2083 | } |
| 2084 | BLOCK_END | ||
| 2085 | auto tmpChain = x->new_ptr<ChainValue_t>(); | ||
| 2086 | for (auto item : chain->items.objects()) { | ||
| 2087 | bool itemAdded = false; | ||
| 2088 | BLOCK_START | ||
| 2089 | auto exp = ast_cast<Exp_t>(item); | ||
| 2090 | BREAK_IF(!exp); | ||
| 2091 | auto var = singleVariableFrom(exp); | ||
| 2092 | BREAK_IF(!var.empty()); | ||
| 2093 | auto upVar = getUnusedName("_update_"sv); | ||
| 2094 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2095 | newAssignment->expList.set(toAst<ExpList_t>(upVar, x)); | ||
| 2096 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2097 | assign->values.push_back(exp); | ||
| 2098 | newAssignment->action.set(assign); | ||
| 2099 | transformAssignment(newAssignment, temp); | ||
| 2100 | tmpChain->items.push_back(toAst<Exp_t>(upVar, x)); | ||
| 2101 | itemAdded = true; | ||
| 2102 | BLOCK_END | ||
| 2103 | if (!itemAdded) tmpChain->items.push_back(item); | ||
| 2104 | } | ||
| 2105 | chain->items.clear(); | ||
| 2106 | chain->items.dup(tmpChain->items); | ||
| 2107 | auto op = _parser.toString(update->op); | ||
| 2094 | if (op == "??"sv) { | 2108 | if (op == "??"sv) { |
| 2095 | auto defs = getPredefine(assignment); | 2109 | auto defs = getPredefine(assignment); |
| 2096 | auto rightExp = x->new_ptr<Exp_t>(); | 2110 | auto rightExp = x->new_ptr<Exp_t>(); |
| @@ -2101,16 +2115,6 @@ private: | |||
| 2101 | if (!defs.empty()) temp.back().insert(0, defs + nll(x)); | 2115 | if (!defs.empty()) temp.back().insert(0, defs + nll(x)); |
| 2102 | out.push_back(join(temp)); | 2116 | out.push_back(join(temp)); |
| 2103 | return; | 2117 | return; |
| 2104 | } else if (op == "#"sv) { | ||
| 2105 | auto left = _parser.toString(chain->items.front()); | ||
| 2106 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2107 | newAssignment->expList.set(toAst<ExpList_t>(left + "[#"s + left + "+1]"s, x)); | ||
| 2108 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2109 | assign->values.push_back(update->value); | ||
| 2110 | newAssignment->action.set(assign); | ||
| 2111 | transformAssignment(newAssignment, temp); | ||
| 2112 | out.push_back(join(temp)); | ||
| 2113 | return; | ||
| 2114 | } | 2118 | } |
| 2115 | auto defs = getPredefine(assignment); | 2119 | auto defs = getPredefine(assignment); |
| 2116 | transformValue(leftValue, temp); | 2120 | transformValue(leftValue, temp); |
| @@ -3970,6 +3974,9 @@ private: | |||
| 3970 | temp.back() = (temp.back().front() == '[' ? "[ "s : "["s) + temp.back() + ']'; | 3974 | temp.back() = (temp.back().front() == '[' ? "[ "s : "["s) + temp.back() + ']'; |
| 3971 | break; | 3975 | break; |
| 3972 | case id<InvokeArgs_t>(): transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break; | 3976 | case id<InvokeArgs_t>(): transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break; |
| 3977 | case id<table_appending_op_t>(): | ||
| 3978 | transform_table_appending_op(static_cast<table_appending_op_t*>(item), temp); | ||
| 3979 | break; | ||
| 3973 | default: YUEE("AST node mismatch", item); break; | 3980 | default: YUEE("AST node mismatch", item); break; |
| 3974 | } | 3981 | } |
| 3975 | } | 3982 | } |
| @@ -4391,6 +4398,10 @@ private: | |||
| 4391 | throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice)); | 4398 | throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice)); |
| 4392 | } | 4399 | } |
| 4393 | 4400 | ||
| 4401 | void transform_table_appending_op(table_appending_op_t* op, str_list&) { | ||
| 4402 | throw std::logic_error(_info.errorMessage("table appending syntax not supported here"sv, op)); | ||
| 4403 | } | ||
| 4404 | |||
| 4394 | void transformInvoke(Invoke_t* invoke, str_list& out) { | 4405 | void transformInvoke(Invoke_t* invoke, str_list& out) { |
| 4395 | str_list temp; | 4406 | str_list temp; |
| 4396 | for (auto arg : invoke->args.objects()) { | 4407 | for (auto arg : invoke->args.objects()) { |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 772ae08..3d12190 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -324,8 +324,7 @@ YueParser::YueParser() { | |||
| 324 | expr("|") | | 324 | expr("|") | |
| 325 | expr(">>") | | 325 | expr(">>") | |
| 326 | expr("<<") | | 326 | expr("<<") | |
| 327 | expr("??") | | 327 | expr("??"); |
| 328 | expr("#"); | ||
| 329 | 328 | ||
| 330 | Update = Space >> update_op >> expr("=") >> Exp; | 329 | Update = Space >> update_op >> expr("=") >> Exp; |
| 331 | 330 | ||
| @@ -382,7 +381,7 @@ YueParser::YueParser() { | |||
| 382 | return st->chainBlockStack.empty() || st->chainBlockStack.top(); | 381 | return st->chainBlockStack.empty() || st->chainBlockStack.top(); |
| 383 | }) >> +SpaceBreak >> Advance >> ensure( | 382 | }) >> +SpaceBreak >> Advance >> ensure( |
| 384 | chain_line >> *(+SpaceBreak >> chain_line), PopIndent); | 383 | chain_line >> *(+SpaceBreak >> chain_line), PopIndent); |
| 385 | ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block); | 384 | ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; |
| 386 | 385 | ||
| 387 | simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); | 386 | simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); |
| 388 | Value = SimpleValue | simple_table | ChainValue | String; | 387 | Value = SimpleValue | simple_table | ChainValue | String; |
| @@ -427,6 +426,7 @@ YueParser::YueParser() { | |||
| 427 | Metamethod = Name >> expr('#'); | 426 | Metamethod = Name >> expr('#'); |
| 428 | 427 | ||
| 429 | existential_op = expr('?') >> not_(expr('?')); | 428 | existential_op = expr('?') >> not_(expr('?')); |
| 429 | table_appending_op = expr("[]"); | ||
| 430 | chain_call = (Callable | String) >> -existential_op >> ChainItems; | 430 | chain_call = (Callable | String) >> -existential_op >> ChainItems; |
| 431 | chain_item = and_(set(".\\")) >> ChainItems; | 431 | chain_item = and_(set(".\\")) >> ChainItems; |
| 432 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; | 432 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index e128e82..7dea126 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -277,6 +277,7 @@ private: | |||
| 277 | AST_RULE(Slice) | 277 | AST_RULE(Slice) |
| 278 | AST_RULE(Invoke) | 278 | AST_RULE(Invoke) |
| 279 | AST_RULE(existential_op) | 279 | AST_RULE(existential_op) |
| 280 | AST_RULE(table_appending_op) | ||
| 280 | AST_RULE(TableLit) | 281 | AST_RULE(TableLit) |
| 281 | AST_RULE(TableBlock) | 282 | AST_RULE(TableBlock) |
| 282 | AST_RULE(TableBlockIndent) | 283 | AST_RULE(TableBlockIndent) |
