mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
666 lines
31 KiB
Text
666 lines
31 KiB
Text
|
# 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
|