diff options
Diffstat (limited to 'test/racc/assets/riml.y')
-rw-r--r-- | test/racc/assets/riml.y | 665 |
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 |