summaryrefslogtreecommitdiff
path: root/test/racc/assets/riml.y
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2019-05-13 21:25:22 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2019-06-19 18:17:25 +0900
commit1a2546c2be839baa7d0a50dc056d4d6987d26852 (patch)
tree19fef5d8b8d96452a51ab68e8093ea895192ca27 /test/racc/assets/riml.y
parentcbe06cd3501fdadd0e6e63094da2973484d70b0b (diff)
Backport racc-1.4.15 from upstream.
Diffstat (limited to 'test/racc/assets/riml.y')
-rw-r--r--test/racc/assets/riml.y665
1 files changed, 665 insertions, 0 deletions
diff --git a/test/racc/assets/riml.y b/test/racc/assets/riml.y
new file mode 100644
index 0000000000..1d99b0fdb8
--- /dev/null
+++ b/test/racc/assets/riml.y
@@ -0,0 +1,665 @@
+# Copyright (c) 2012-2014 by Luke Gruber
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# 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.
+
+class Riml::Parser
+
+token IF ELSE ELSEIF THEN UNLESS END
+token WHILE UNTIL BREAK CONTINUE
+token TRY CATCH FINALLY
+token FOR IN
+token DEF DEF_BANG SPLAT_PARAM SPLAT_ARG CALL BUILTIN_COMMAND # such as echo "hi"
+token CLASS NEW DEFM DEFM_BANG SUPER
+token RIML_FILE_COMMAND RIML_CLASS_COMMAND
+token RETURN
+token NEWLINE
+token NUMBER
+token STRING_D STRING_S # single- and double-quoted
+token EX_LITERAL
+token REGEXP
+token TRUE FALSE
+token LET UNLET UNLET_BANG IDENTIFIER
+token DICT_VAL # like dict.key, 'key' is a DICT_VAL
+token SCOPE_MODIFIER SCOPE_MODIFIER_LITERAL SPECIAL_VAR_PREFIX
+token FINISH
+
+prechigh
+ right '!'
+ left '*' '/' '%'
+ left '+' '-' '.'
+ left '>' '>#' '>?' '<' '<#' '<?' '>=' '>=#' '>=?' '<=' '<=#' '<=?'
+ left '==' '==?' '==#' '=~' '=~?' '=~#' '!~' '!~?' '!~#' '!=' '!=?' '!=#'
+ left IS ISNOT
+ left '&&'
+ left '||'
+ right '?'
+ right '=' '+=' '-=' '.='
+ left ','
+ left IF UNLESS
+preclow
+
+# All rules
+rule
+
+ Root:
+ /* nothing */ { result = make_node(val) { |_| Riml::Nodes.new([]) } }
+ | Terminator { result = make_node(val) { |_| Riml::Nodes.new([]) } }
+ | Statements { result = val[0] }
+ ;
+
+ # any list of expressions
+ Statements:
+ Statement { result = make_node(val) { |v| Riml::Nodes.new([ v[0] ]) } }
+ | Statements Terminator Statement { result = val[0] << val[2] }
+ | Statements Terminator { result = val[0] }
+ | Terminator Statements { result = make_node(val) { |v| Riml::Nodes.new(v[1]) } }
+ ;
+
+ # All types of expressions in Riml
+ Statement:
+ ExplicitCall { result = val[0] }
+ | Def { result = val[0] }
+ | Return { result = val[0] }
+ | UnletVariable { result = val[0] }
+ | ExLiteral { result = val[0] }
+ | For { result = val[0] }
+ | While { result = val[0] }
+ | Until { result = val[0] }
+ | Try { result = val[0] }
+ | ClassDefinition { result = val[0] }
+ | LoopKeyword { result = val[0] }
+ | EndScript { result = val[0] }
+ | RimlFileCommand { result = val[0] }
+ | RimlClassCommand { result = val[0] }
+ | MultiAssign { result = val[0] }
+ | If { result = val[0] }
+ | Unless { result = val[0] }
+ | Expression { result = val[0] }
+ ;
+
+ Expression:
+ ExpressionWithoutDictLiteral { result = val[0] }
+ | Dictionary { result = val[0] }
+ | Dictionary DictGetWithDotLiteral { result = make_node(val) { |v| Riml::DictGetDotNode.new(v[0], v[1]) } }
+ | BinaryOperator { result = val[0] }
+ | Ternary { result = val[0] }
+ | Assign { result = val[0] }
+ | Super { result = val[0] }
+ | '(' Expression ')' { result = make_node(val) { |v| Riml::WrapInParensNode.new(v[1]) } }
+ ;
+
+ ExpressionWithoutDictLiteral:
+ UnaryOperator { result = val[0] }
+ | DictGet { result = val[0] }
+ | ListOrDictGet { result = val[0] }
+ | AllVariableRetrieval { result = val[0] }
+ | LiteralWithoutDictLiteral { result = val[0] }
+ | Call { result = val[0] }
+ | ObjectInstantiation { result = val[0] }
+ | '(' ExpressionWithoutDictLiteral ')' { result = make_node(val) { |v| Riml::WrapInParensNode.new(v[1]) } }
+ ;
+
+ # for inside curly-brace variable names
+ PossibleStringValue:
+ String { result = val[0] }
+ | DictGet { result = val[0] }
+ | ListOrDictGet { result = val[0] }
+ | AllVariableRetrieval { result = val[0] }
+ | BinaryOperator { result = val[0] }
+ | Ternary { result = val[0] }
+ | Call { result = val[0] }
+ ;
+
+ Terminator:
+ NEWLINE { result = nil }
+ | ';' { result = nil }
+ ;
+
+ LiteralWithoutDictLiteral:
+ Number { result = val[0] }
+ | String { result = val[0] }
+ | Regexp { result = val[0] }
+ | List { result = val[0] }
+ | ScopeModifierLiteral { result = val[0] }
+ | TRUE { result = make_node(val) { |_| Riml::TrueNode.new } }
+ | FALSE { result = make_node(val) { |_| Riml::FalseNode.new } }
+ ;
+
+ Number:
+ NUMBER { result = make_node(val) { |v| Riml::NumberNode.new(v[0]) } }
+ ;
+
+ String:
+ STRING_S { result = make_node(val) { |v| Riml::StringNode.new(v[0], :s) } }
+ | STRING_D { result = make_node(val) { |v| Riml::StringNode.new(v[0], :d) } }
+ | String STRING_S { result = make_node(val) { |v| Riml::StringLiteralConcatNode.new(v[0], Riml::StringNode.new(v[1], :s)) } }
+ | String STRING_D { result = make_node(val) { |v| Riml::StringLiteralConcatNode.new(v[0], Riml::StringNode.new(v[1], :d)) } }
+ ;
+
+ Regexp:
+ REGEXP { result = make_node(val) { |v| Riml::RegexpNode.new(v[0]) } }
+ ;
+
+ ScopeModifierLiteral:
+ SCOPE_MODIFIER_LITERAL { result = make_node(val) { |v| Riml::ScopeModifierLiteralNode.new(v[0]) } }
+ ;
+
+ List:
+ ListLiteral { result = make_node(val) { |v| Riml::ListNode.new(v[0]) } }
+ ;
+
+ ListUnpack:
+ '[' ListItems ';' Expression ']' { result = make_node(val) { |v| Riml::ListUnpackNode.new(v[1] << v[3]) } }
+ ;
+
+ ListLiteral:
+ '[' ListItems ']' { result = val[1] }
+ | '[' ListItems ',' ']' { result = val[1] }
+ ;
+
+ ListItems:
+ /* nothing */ { result = [] }
+ | Expression { result = [val[0]] }
+ | ListItems ',' Expression { result = val[0] << val[2] }
+ ;
+
+ Dictionary:
+ DictionaryLiteral { result = make_node(val) { |v| Riml::DictionaryNode.new(v[0]) } }
+ ;
+
+ # {'key': 'value', 'key2': 'value2'}
+ # Save as [['key', 'value'], ['key2', 'value2']] because ruby-1.8.7 offers
+ # no guarantee for key-value pair ordering.
+ DictionaryLiteral:
+ '{' DictItems '}' { result = val[1] }
+ | '{' DictItems ',' '}' { result = val[1] }
+ ;
+
+ # [[key, value], [key, value]]
+ DictItems:
+ /* nothing */ { result = [] }
+ | DictItem { result = val }
+ | DictItems ',' DictItem { result = val[0] << val[2] }
+ ;
+
+ # [key, value]
+ DictItem:
+ Expression ':' Expression { result = [val[0], val[2]] }
+ ;
+
+ DictGet:
+ AllVariableRetrieval DictGetWithDot { result = make_node(val) { |v| Riml::DictGetDotNode.new(v[0], v[1]) } }
+ | ListOrDictGet DictGetWithDot { result = make_node(val) { |v| Riml::DictGetDotNode.new(v[0], v[1]) } }
+ | Call DictGetWithDot { result = make_node(val) { |v| Riml::DictGetDotNode.new(v[0], v[1]) } }
+ | '(' Expression ')' DictGetWithDot { result = make_node(val) { |v| Riml::DictGetDotNode.new(Riml::WrapInParensNode.new(v[1]), v[3]) } }
+ ;
+
+ ListOrDictGet:
+ ExpressionWithoutDictLiteral ListOrDictGetWithBrackets { result = make_node(val) { |v| Riml::ListOrDictGetNode.new(v[0], v[1]) } }
+ | '(' Expression ')' ListOrDictGetWithBrackets { result = make_node(val) { |v| Riml::ListOrDictGetNode.new(Riml::WrapInParensNode.new(v[1]), v[3]) } }
+ ;
+
+ ListOrDictGetAssign:
+ ExpressionWithoutDictLiteral ListOrDictGetWithBrackets { result = make_node(val) { |v| Riml::ListOrDictGetNode.new(v[0], v[1]) } }
+ ;
+
+ ListOrDictGetWithBrackets:
+ '[' Expression ']' { result = [val[1]] }
+ | '[' SubList ']' { result = [val[1]] }
+ | ListOrDictGetWithBrackets '[' Expression ']' { result = val[0] << val[2] }
+ | ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
+ ;
+
+ SubList:
+ Expression ':' Expression { result = make_node(val) { |v| Riml::SublistNode.new([v[0], Riml::LiteralNode.new(' : '), v[2]]) } }
+ | Expression ':' { result = make_node(val) { |v| Riml::SublistNode.new([v[0], Riml::LiteralNode.new(' :')]) } }
+ | ':' Expression { result = make_node(val) { |v| Riml::SublistNode.new([Riml::LiteralNode.new(': '), v[1]]) } }
+ | ':' { result = make_node(val) { |_| Riml::SublistNode.new([Riml::LiteralNode.new(':')]) } }
+ ;
+
+ DictGetWithDot:
+ DICT_VAL { result = [val[0]] }
+ | DictGetWithDot DICT_VAL { result = val[0] << val[1] }
+ ;
+
+ DictGetWithDotLiteral:
+ '.' IDENTIFIER { result = [val[1]] }
+ | DictGetWithDotLiteral DICT_VAL { result = val[0] << val[1] }
+ ;
+
+ Call:
+ Scope DefCallIdentifier '(' ArgList ')' { result = make_node(val) { |v| Riml::CallNode.new(v[0], v[1], v[3]) } }
+ | DictGet '(' ArgList ')' { result = make_node(val) { |v| Riml::CallNode.new(nil, v[0], v[2]) } }
+ | BUILTIN_COMMAND '(' ArgList ')' { result = make_node(val) { |v| Riml::CallNode.new(nil, v[0], v[2]) } }
+ | BUILTIN_COMMAND ArgListWithoutNothing { result = make_node(val) { |v| Riml::CallNode.new(nil, v[0], v[1]) } }
+ | BUILTIN_COMMAND NEWLINE { result = make_node(val) { |v| Riml::CallNode.new(nil, v[0], []) } }
+ | CALL '(' ArgList ')' { result = make_node(val) { |v| Riml::ExplicitCallNode.new(nil, nil, v[2]) } }
+ ;
+
+ ObjectInstantiationCall:
+ Scope DefCallIdentifier '(' ArgList ')' { result = make_node(val) { |v| Riml::CallNode.new(v[0], v[1], v[3]) } }
+ | Scope DefCallIdentifier { result = make_node(val) { |v| Riml::CallNode.new(v[0], v[1], []) } }
+ ;
+
+ RimlFileCommand:
+ RIML_FILE_COMMAND '(' ArgList ')' { result = make_node(val) { |v| Riml::RimlFileCommandNode.new(nil, v[0], v[2]) } }
+ | RIML_FILE_COMMAND ArgList { result = make_node(val) { |v| Riml::RimlFileCommandNode.new(nil, v[0], v[1]) } }
+ ;
+
+ RimlClassCommand:
+ RIML_CLASS_COMMAND '(' ClassArgList ')' { result = make_node(val) { |v| Riml::RimlClassCommandNode.new(nil, v[0], v[2]) } }
+ | RIML_CLASS_COMMAND ClassArgList { result = make_node(val) { |v| Riml::RimlClassCommandNode.new(nil, v[0], v[1]) } }
+ ;
+
+ ClassArgList:
+ Scope IDENTIFIER { result = ["#{val[0]}#{val[1]}"] }
+ | String { result = val }
+ | ClassArgList ',' Scope IDENTIFIER { result = val[0].concat ["#{val[2]}#{val[3]}"] }
+ ;
+
+ ExplicitCall:
+ CALL Scope DefCallIdentifier '(' ArgList ')' { result = make_node(val) { |v| Riml::ExplicitCallNode.new(v[1], v[2], v[4]) } }
+ | CALL DictGet '(' ArgList ')' { result = make_node(val) { |v| Riml::ExplicitCallNode.new(nil, v[1], v[3]) } }
+ ;
+
+ Scope:
+ SCOPE_MODIFIER { result = val[0] }
+ | /* nothing */ { result = nil }
+ ;
+
+ # [SID, scope_modifier]
+ SIDAndScope:
+ Scope { result = [ nil, val[0] ] }
+ | '<' IDENTIFIER '>' Scope { result = [ make_node(val) { |v| Riml::SIDNode.new(v[1]) }, val[3] ] }
+ ;
+
+ ArgList:
+ /* nothing */ { result = [] }
+ | ArgListWithoutNothingWithSplat { result = val[0] }
+ ;
+
+ ArgListWithSplat:
+ /* nothing */ { result = [] }
+ | ArgListWithoutNothingWithSplat { result = val[0] }
+ ;
+
+ ArgListWithoutNothingWithSplat:
+ Expression { result = val }
+ | SPLAT_ARG Expression { result = [ make_node(val) { |v| Riml::SplatNode.new(v[1]) } ] }
+ | ArgListWithoutNothingWithSplat "," Expression { result = val[0] << val[2] }
+ | ArgListWithoutNothingWithSplat "," SPLAT_ARG Expression { result = val[0] << make_node(val) { |v| Riml::SplatNode.new(v[3]) } }
+ ;
+
+ ArgListWithoutNothing:
+ Expression { result = val }
+ | ArgListWithoutNothing "," Expression { result = val[0] << val[2] }
+ ;
+
+ BinaryOperator:
+ Expression '||' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '&&' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '==' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '==#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '==?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ # added by riml
+ | Expression '===' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '!=' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '!=#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '!=?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '=~' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '=~#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '=~?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '!~' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '!~#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '!~?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '>' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '>#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '>?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '>=' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '>=#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '>=?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '<' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '<#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '<?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '<=' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '<=#' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '<=?' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression '+' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '-' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '*' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '/' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '.' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression '%' Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+
+ | Expression IS Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ | Expression ISNOT Expression { result = make_node(val) { |v| Riml::BinaryOperatorNode.new(v[1], [v[0], v[2]]) } }
+ ;
+
+ UnaryOperator:
+ '!' Expression { result = make_node(val) { |v| Riml::UnaryOperatorNode.new(val[0], [val[1]]) } }
+ | '+' Expression { result = make_node(val) { |v| Riml::UnaryOperatorNode.new(val[0], [val[1]]) } }
+ | '-' Expression { result = make_node(val) { |v| Riml::UnaryOperatorNode.new(val[0], [val[1]]) } }
+ ;
+
+ # ['=', LHS, RHS]
+ Assign:
+ LET AssignExpression { result = make_node(val) { |v| Riml::AssignNode.new(v[1][0], v[1][1], v[1][2]) } }
+ | AssignExpression { result = make_node(val) { |v| Riml::AssignNode.new(v[0][0], v[0][1], v[0][2]) } }
+ ;
+
+ MultiAssign:
+ Assign ',' Assign { result = make_node(val) { |v| Riml::MultiAssignNode.new([v[0], v[2]]) } }
+ | MultiAssign ',' Assign { val[0].assigns << val[2]; result = val[0] }
+ ;
+
+ # ['=', AssignLHS, Expression]
+ AssignExpression:
+ AssignLHS '=' Expression { result = [val[1], val[0], val[2]] }
+ | AssignLHS '+=' Expression { result = [val[1], val[0], val[2]] }
+ | AssignLHS '-=' Expression { result = [val[1], val[0], val[2]] }
+ | AssignLHS '.=' Expression { result = [val[1], val[0], val[2]] }
+ ;
+
+ AssignLHS:
+ AllVariableRetrieval { result = val[0] }
+ | List { result = val[0] }
+ | ListUnpack { result = val[0] }
+ | DictGet { result = val[0] }
+ | ListOrDictGetAssign { result = val[0] }
+ ;
+
+ # retrieving the value of a variable
+ VariableRetrieval:
+ SimpleVariableRetrieval { result = val[0] }
+ | SPECIAL_VAR_PREFIX IDENTIFIER { result = make_node(val) { |v| Riml::GetSpecialVariableNode.new(v[0], v[1]) } }
+ | ScopeModifierLiteral ListOrDictGetWithBrackets { result = make_node(val) { |v| Riml::GetVariableByScopeAndDictNameNode.new(v[0], v[1]) } }
+ ;
+
+ SimpleVariableRetrieval:
+ Scope IDENTIFIER { result = make_node(val) { |v| Riml::GetVariableNode.new(v[0], v[1]) } }
+ ;
+
+ AllVariableRetrieval:
+ VariableRetrieval { result = val[0] }
+ | Scope CurlyBraceName { result = make_node(val) { |v| Riml::GetCurlyBraceNameNode.new(v[0], v[1]) } }
+ ;
+
+ UnletVariable:
+ UNLET VariableRetrieval { result = make_node(val) { |v| Riml::UnletVariableNode.new('!', [ v[1] ]) } }
+ | UNLET_BANG VariableRetrieval { result = make_node(val) { |v| Riml::UnletVariableNode.new('!', [ v[1] ]) } }
+ | UnletVariable VariableRetrieval { result = val[0] << val[1] }
+ ;
+
+ CurlyBraceName:
+ CurlyBraceVarPart { result = make_node(val) { |v| Riml::CurlyBraceVariable.new([ v[0] ]) } }
+ | IDENTIFIER CurlyBraceName { result = make_node(val) { |v| Riml::CurlyBraceVariable.new([ Riml::CurlyBracePart.new(v[0]), v[1] ]) } }
+ | CurlyBraceName IDENTIFIER { result = val[0] << make_node(val) { |v| Riml::CurlyBracePart.new(v[1]) } }
+ | CurlyBraceName CurlyBraceVarPart { result = val[0] << val[1] }
+ ;
+
+ CurlyBraceVarPart:
+ '{' PossibleStringValue '}' { result = make_node(val) { |v| Riml::CurlyBracePart.new(v[1]) } }
+ | '{' PossibleStringValue CurlyBraceVarPart '}' { result = make_node(val) { |v| Riml::CurlyBracePart.new([v[1], v[2]]) } }
+ | '{' CurlyBraceVarPart PossibleStringValue '}' { result = make_node(val) { |v| Riml::CurlyBracePart.new([v[1], v[2]]) } }
+ ;
+
+ # Method definition
+ # [SID, scope_modifier, name, parameters, keyword, expressions]
+ Def:
+ FunctionType SIDAndScope DefCallIdentifier DefKeywords Block END { result = make_node(val) { |v| Riml.const_get(val[0]).new('!', v[1][0], v[1][1], v[2], [], v[3], v[4]) } }
+ | FunctionType SIDAndScope DefCallIdentifier '(' ParamList ')' DefKeywords Block END { result = make_node(val) { |v| Riml.const_get(val[0]).new('!', v[1][0], v[1][1], v[2], v[4], v[6], v[7]) } }
+ | FunctionType SIDAndScope DefCallIdentifier '(' SPLAT_PARAM ')' DefKeywords Block END { result = make_node(val) { |v| Riml.const_get(val[0]).new('!', v[1][0], v[1][1], v[2], [v[4]], v[6], v[7]) } }
+ | FunctionType SIDAndScope DefCallIdentifier '(' ParamList ',' SPLAT_PARAM ')' DefKeywords Block END { result = make_node(val) { |v| Riml.const_get(val[0]).new('!', v[1][0], v[1][1], v[2], v[4] << v[6], v[8], v[9]) } }
+ ;
+
+ FunctionType:
+ DEF { result = "DefNode" }
+ | DEF_BANG { result = "DefNode" }
+ | DEFM { result = "DefMethodNode" }
+ ;
+
+ DefCallIdentifier:
+ # use '' for first argument instead of nil in order to avoid a double scope-modifier
+ CurlyBraceName { result = make_node(val) { |v| Riml::GetCurlyBraceNameNode.new('', v[0]) } }
+ | IDENTIFIER { result = val[0] }
+ ;
+
+ # Example: 'range', 'dict' or 'abort' after function definition
+ DefKeywords:
+ IDENTIFIER { result = [val[0]] }
+ | DefKeywords IDENTIFIER { result = val[0] << val[1] }
+ | /* nothing */ { result = nil }
+ ;
+
+ ParamList:
+ /* nothing */ { result = [] }
+ | IDENTIFIER { result = val }
+ | DefaultParam { result = val }
+ | ParamList ',' IDENTIFIER { result = val[0] << val[2] }
+ | ParamList ',' DefaultParam { result = val[0] << val[2] }
+ ;
+
+ DefaultParam:
+ IDENTIFIER '=' Expression { result = make_node(val) { |v| Riml::DefaultParamNode.new(v[0], v[2]) } }
+ ;
+
+ Return:
+ RETURN Returnable { result = make_node(val) { |v| Riml::ReturnNode.new(v[1]) } }
+ | RETURN Returnable IF Expression { result = make_node(val) { |v| Riml::IfNode.new(v[3], Nodes.new([ReturnNode.new(v[1])])) } }
+ | RETURN Returnable UNLESS Expression { result = make_node(val) { |v| Riml::UnlessNode.new(v[3], Nodes.new([ReturnNode.new(v[1])])) } }
+ ;
+
+ Returnable:
+ /* nothing */ { result = nil }
+ | Expression { result = val[0] }
+ ;
+
+ EndScript:
+ FINISH { result = make_node(val) { |_| Riml::FinishNode.new } }
+ ;
+
+ # [expression, expressions]
+ If:
+ IF Expression IfBlock END { result = make_node(val) { |v| Riml::IfNode.new(v[1], v[2]) } }
+ | IF Expression THEN Expression END { result = make_node(val) { |v| Riml::IfNode.new(v[1], Riml::Nodes.new([v[3]])) } }
+ | Expression IF Expression { result = make_node(val) { |v| Riml::IfNode.new(v[2], Riml::Nodes.new([v[0]])) } }
+ ;
+
+ Unless:
+ UNLESS Expression IfBlock END { result = make_node(val) { |v| Riml::UnlessNode.new(v[1], v[2]) } }
+ | UNLESS Expression THEN Expression END { result = make_node(val) { |v| Riml::UnlessNode.new(v[1], Riml::Nodes.new([v[3]])) } }
+ | Expression UNLESS Expression { result = make_node(val) { |v| Riml::UnlessNode.new(v[2], Riml::Nodes.new([v[0]])) } }
+ ;
+
+ Ternary:
+ Expression '?' Expression ':' Expression { result = make_node(val) { |v| Riml::TernaryOperatorNode.new([v[0], v[2], v[4]]) } }
+ ;
+
+ While:
+ WHILE Expression Block END { result = make_node(val) { |v| Riml::WhileNode.new(v[1], v[2]) } }
+ ;
+
+ LoopKeyword:
+ BREAK { result = make_node(val) { |_| Riml::BreakNode.new } }
+ | CONTINUE { result = make_node(val) { |_| Riml::ContinueNode.new } }
+ ;
+
+ Until:
+ UNTIL Expression Block END { result = make_node(val) { |v| Riml::UntilNode.new(v[1], v[2]) } }
+ ;
+
+ For:
+ FOR SimpleVariableRetrieval IN Expression Block END { result = make_node(val) { |v| Riml::ForNode.new(v[1], v[3], v[4]) } }
+ | FOR List IN Expression Block END { result = make_node(val) { |v| Riml::ForNode.new(v[1], v[3], v[4]) } }
+ | FOR ListUnpack IN Expression Block END { result = make_node(val) { |v| Riml::ForNode.new(v[1], v[3], v[4]) } }
+ ;
+
+ Try:
+ TRY Block END { result = make_node(val) { |v| Riml::TryNode.new(v[1], nil, nil) } }
+ | TRY Block Catch END { result = make_node(val) { |v| Riml::TryNode.new(v[1], v[2], nil) } }
+ | TRY Block Catch FINALLY Block END { result = make_node(val) { |v| Riml::TryNode.new(v[1], v[2], v[4]) } }
+ ;
+
+ Catch:
+ /* nothing */ { result = nil }
+ | CATCH Block { result = [ make_node(val) { |v| Riml::CatchNode.new(nil, v[1]) } ] }
+ | CATCH Catchable Block { result = [ make_node(val) { |v| Riml::CatchNode.new(v[1], v[2]) } ] }
+ | Catch CATCH Block { result = val[0] << make_node(val) { |v| Riml::CatchNode.new(nil, v[2]) } }
+ | Catch CATCH Catchable Block { result = val[0] << make_node(val) { |v| Riml::CatchNode.new(v[2], v[3]) } }
+ ;
+
+ Catchable:
+ Regexp { result = val[0] }
+ | String { result = val[0] }
+ ;
+
+ # [expressions]
+ # expressions list could contain an ElseNode, which contains expressions
+ # itself
+ Block:
+ NEWLINE Statements { result = val[1] }
+ | NEWLINE { result = make_node(val) { |_| Riml::Nodes.new([]) } }
+ ;
+
+ IfBlock:
+ Block { result = val[0] }
+ | NEWLINE Statements ElseBlock { result = val[1] << val[2] }
+ | NEWLINE Statements ElseifBlock { result = val[1] << val[2] }
+ | NEWLINE Statements ElseifBlock ElseBlock { result = val[1] << val[2] << val[3] }
+ ;
+
+ ElseBlock:
+ ELSE NEWLINE Statements { result = make_node(val) { |v| Riml::ElseNode.new(v[2]) } }
+ ;
+
+ ElseifBlock:
+ ELSEIF Expression NEWLINE Statements { result = make_node(val) { |v| Riml::Nodes.new([Riml::ElseifNode.new(v[1], v[3])]) } }
+ | ElseifBlock ELSEIF Expression NEWLINE Statements { result = val[0] << make_node(val) { |v| Riml::ElseifNode.new(v[2], v[4]) } }
+ ;
+
+ ClassDefinition:
+ CLASS Scope IDENTIFIER Block END { result = make_node(val) { |v| Riml::ClassDefinitionNode.new(v[1], v[2], nil, v[3]) } }
+ | CLASS Scope IDENTIFIER '<' Scope IDENTIFIER Block END { result = make_node(val) { |v| Riml::ClassDefinitionNode.new(v[1], v[2], (v[4] || ClassDefinitionNode::DEFAULT_SCOPE_MODIFIER) + v[5], v[6]) } }
+ ;
+
+ ObjectInstantiation:
+ NEW ObjectInstantiationCall { result = make_node(val) { |v| Riml::ObjectInstantiationNode.new(v[1]) } }
+ ;
+
+ Super:
+ SUPER '(' ArgListWithSplat ')' { result = make_node(val) { |v| Riml::SuperNode.new(v[2], true) } }
+ | SUPER { result = make_node(val) { |_| Riml::SuperNode.new([], false) } }
+ ;
+
+ ExLiteral:
+ EX_LITERAL { result = make_node(val) { |v| Riml::ExLiteralNode.new(v[0]) } }
+ ;
+end
+
+---- header
+ require File.expand_path("../lexer", __FILE__)
+ require File.expand_path("../nodes", __FILE__)
+ require File.expand_path("../errors", __FILE__)
+ require File.expand_path("../ast_rewriter", __FILE__)
+---- inner
+ # This code will be put as-is in the parser class
+
+ attr_accessor :ast_rewriter
+ attr_writer :options
+
+ # The Parser and AST_Rewriter share this same hash of options
+ def options
+ @options ||= {}
+ end
+
+ def self.ast_cache
+ @ast_cache
+ end
+ @ast_cache = {}
+
+ # parses tokens or code into output nodes
+ def parse(object, ast_rewriter = Riml::AST_Rewriter.new, filename = nil, included = false)
+ if (ast = self.class.ast_cache[filename])
+ else
+ if tokens?(object)
+ @tokens = object
+ elsif code?(object)
+ @lexer = Riml::Lexer.new(object, filename, true)
+ end
+
+ begin
+ ast = do_parse
+ rescue Racc::ParseError => e
+ raise unless @lexer
+ if (invalid_token = @lexer.prev_token_is_keyword?)
+ warning = "#{invalid_token.inspect} is a keyword, and cannot " \
+ "be used as a variable name"
+ end
+ error_msg = e.message
+ error_msg << "\nWARNING: #{warning}" if warning
+ error = Riml::ParseError.new(error_msg, @lexer.filename, @lexer.lineno)
+ raise error
+ end
+ self.class.ast_cache[filename] = ast if filename
+ end
+ @ast_rewriter ||= ast_rewriter
+ return ast unless @ast_rewriter
+ @ast_rewriter.ast = ast.dup
+ @ast_rewriter.options ||= options
+ @ast_rewriter.rewrite(filename, included)
+ @ast_rewriter.ast
+ end
+
+ # get the next token from either the list of tokens provided, or
+ # the lexer getting the next token
+ def next_token
+ return @tokens.shift unless @lexer
+ token = @lexer.next_token
+ if token && @lexer.parser_info
+ @current_parser_info = token.pop
+ end
+ token
+ end
+
+ private
+
+ def tokens?(object)
+ Array === object
+ end
+
+ def code?(object)
+ String === object
+ end
+
+ def make_node(racc_val)
+ node = yield racc_val
+ node.parser_info = @current_parser_info
+ node
+ end