├── .gitignore ├── README ├── array_literal.rb ├── array_literal_e.rb ├── bin ├── sbt ├── sbt-launch-lib.bash ├── sbt-launch.jar └── sbt.bat ├── build.sbt ├── heredoc.rb ├── project ├── build.properties └── plugins.sbt └── src └── main └── scala └── com └── github └── inakata └── ruby_scala ├── Ruby.scala ├── RubyParser.scala └── TracableParsers.scala /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | lib_managed 3 | src_managed 4 | project/boot 5 | project/plugins/project 6 | .project 7 | .classpath 8 | .cache 9 | .settings/ 10 | .idea 11 | .idea_modules 12 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Ruby.scala is a simple parser written in the language Scala by using 2 | parser combinators for ISO Ruby, ISO/IEC 30170:2012. It is written by 3 | Dr. Ikuo Nakata, the chairman of the working group for the standardization 4 | of the language Ruby, with the help by Dr. Kota Mizushima, a deputation of 5 | Japan Scala Users Group and working at Ubiregi Inc. 6 | 7 | Ruby.scala directly follows the syntax of ISO Ruby, except the following: 8 | 9 | 1. The left recursions are eliminated. 10 | 11 | 2. A local-variable-identifier which begins with the letter 'm' is 12 | considered as a method name. Any other local-variable-identifiers are 13 | considered as local variable names. 14 | 15 | 3. The nested brackets in an array-literal are not permitted. 16 | 17 | 4. The production rules for multiple-right-hand-side, class-definition, 18 | method-definition and singleton-method-definition are corrected as follows: 19 | 20 | 11.4.2.4 21 | multiple-right-hand-side :: 22 | operator-expression-list [no line-terminator here] , splatting-right-hand-side 23 | | operator-expression [no line-terminator here] , operator-expression-list 24 | | splatting-right-hand-side 25 | 26 | 13.2.2 27 | class-definition :: 28 | class class-path ( [no line-terminator here] < superclass )? 29 | separator class-body end 30 | 31 | 13.3.1 32 | method-definition :: 33 | def defined-method-name 34 | ( [no line-terminator here] method-parameter-part | separator ) 35 | method-body end 36 | 37 | 13.4.3 38 | singleton-method-definition :: 39 | def singleton-object ( . | :: ) defined-method-name 40 | ( [no line-terminator here] method-parameter-part | separator ) 41 | method-body end 42 | 43 | 5. "method-identifier block" in the right hand of production of primary-method- 44 | invocation (11.3.1) is changed to "method-identifier block?". 45 | 46 | 6. Expressions which end with a do-block are not permitted as the expression in 47 | while-expression, until-expression or for-expression. 48 | 49 | Usage: 50 | 51 | $ scalac Ruby.scala 52 | 53 | $ scala -cp . RubyParser test.rb 54 | 55 | Example 1: 56 | ------ test.rb -------- 57 | class X 58 | @@a = 'abc' 59 | def mprint_a 60 | mputs @@a 61 | end 62 | def mset_a(value) 63 | @@a = value 64 | end 65 | end 66 | ----------------------- 67 | 68 | ------- output -------- 69 | class X 70 | var-assign-ex(@@a='abc') 71 | def mprint_a; 72 | method-inv-without-par(command(mputs @@a)) end-def 73 | def mset_a(value) 74 | var-assign-ex(@@a=value) end-def 75 | end-class 76 | ---------------------- 77 | 78 | Example 2: 79 | ------ test.rb -------- 80 | < path to global settings/plugins directory (default: ~/.sbt) 79 | -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11 series) 80 | -ivy path to local Ivy repository (default: ~/.ivy2) 81 | -mem set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem)) 82 | -no-share use all local caches; no sharing 83 | -no-global uses global caches, but does not use global ~/.sbt directory. 84 | -jvm-debug Turn on JVM debugging, open at the given port. 85 | -batch Disable interactive mode 86 | 87 | # sbt version (default: from project/build.properties if present, else latest release) 88 | -sbt-version use the specified version of sbt 89 | -sbt-jar use the specified jar as the sbt launcher 90 | -sbt-rc use an RC version of sbt 91 | -sbt-snapshot use a snapshot version of sbt 92 | 93 | # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) 94 | -java-home alternate JAVA_HOME 95 | 96 | # jvm options and output control 97 | JAVA_OPTS environment variable, if unset uses "$java_opts" 98 | SBT_OPTS environment variable, if unset uses "$default_sbt_opts" 99 | .sbtopts if this file exists in the current directory, it is 100 | prepended to the runner args 101 | /etc/sbt/sbtopts if this file exists, it is prepended to the runner args 102 | -Dkey=val pass -Dkey=val directly to the java runtime 103 | -J-X pass option -X directly to the java runtime 104 | (-J is stripped) 105 | -S-X add -X to sbt's scalacOptions (-S is stripped) 106 | 107 | In the case of duplicated or conflicting options, the order above 108 | shows precedence: JAVA_OPTS lowest, command line options highest. 109 | EOM 110 | } 111 | 112 | 113 | 114 | process_my_args () { 115 | while [[ $# -gt 0 ]]; do 116 | case "$1" in 117 | -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; 118 | -no-share) addJava "$noshare_opts" && shift ;; 119 | -no-global) addJava "-Dsbt.global.base=$(pwd)/project/.sbtboot" && shift ;; 120 | -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; 121 | -sbt-dir) require_arg path "$1" "$2" && addJava "-Dsbt.global.base=$2" && shift 2 ;; 122 | -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; 123 | -batch) exec &2 "$@" 25 | } 26 | vlog () { 27 | [[ $verbose || $debug ]] && echoerr "$@" 28 | } 29 | dlog () { 30 | [[ $debug ]] && echoerr "$@" 31 | } 32 | 33 | jar_file () { 34 | echo "$(cygwinpath "${sbt_home}/bin/sbt-launch.jar")" 35 | } 36 | 37 | acquire_sbt_jar () { 38 | sbt_jar="$(jar_file)" 39 | 40 | if [[ ! -f "$sbt_jar" ]]; then 41 | echoerr "Could not find launcher jar: $sbt_jar" 42 | exit 2 43 | fi 44 | } 45 | 46 | execRunner () { 47 | # print the arguments one to a line, quoting any containing spaces 48 | [[ $verbose || $debug ]] && echo "# Executing command line:" && { 49 | for arg; do 50 | if printf "%s\n" "$arg" | grep -q ' '; then 51 | printf "\"%s\"\n" "$arg" 52 | else 53 | printf "%s\n" "$arg" 54 | fi 55 | done 56 | echo "" 57 | } 58 | 59 | # THis used to be exec, but we loose the ability to re-hook stty then 60 | # for cygwin... Maybe we should flag the feature here... 61 | "$@" 62 | } 63 | 64 | addJava () { 65 | dlog "[addJava] arg = '$1'" 66 | java_args=( "${java_args[@]}" "$1" ) 67 | } 68 | addSbt () { 69 | dlog "[addSbt] arg = '$1'" 70 | sbt_commands=( "${sbt_commands[@]}" "$1" ) 71 | } 72 | addResidual () { 73 | dlog "[residual] arg = '$1'" 74 | residual_args=( "${residual_args[@]}" "$1" ) 75 | } 76 | addDebugger () { 77 | addJava "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1" 78 | } 79 | 80 | # a ham-fisted attempt to move some memory settings in concert 81 | # so they need not be dorked around with individually. 82 | get_mem_opts () { 83 | local mem=${1:-1024} 84 | local perm=$(( $mem / 4 )) 85 | (( $perm > 256 )) || perm=256 86 | (( $perm < 1024 )) || perm=1024 87 | local codecache=$(( $perm / 2 )) 88 | 89 | echo "-Xms${mem}m -Xmx${mem}m -XX:MaxPermSize=${perm}m -XX:ReservedCodeCacheSize=${codecache}m" 90 | } 91 | 92 | require_arg () { 93 | local type="$1" 94 | local opt="$2" 95 | local arg="$3" 96 | if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then 97 | echo "$opt requires <$type> argument" 98 | exit 1 99 | fi 100 | } 101 | 102 | is_function_defined() { 103 | declare -f "$1" > /dev/null 104 | } 105 | 106 | process_args () { 107 | while [[ $# -gt 0 ]]; do 108 | case "$1" in 109 | -h|-help) usage; exit 1 ;; 110 | -v|-verbose) verbose=1 && shift ;; 111 | -d|-debug) debug=1 && shift ;; 112 | 113 | -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; 114 | -mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;; 115 | -jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;; 116 | -batch) exec &1 | awk -F '"' '/version/ {print $2}') 140 | if [[ "$java_version" == "" ]]; then 141 | echo 142 | echo No java installations was detected. 143 | echo Please go to http://www.java.com/getjava/ and download 144 | echo 145 | exit 1 146 | elif [[ ! "$java_version" > "$required_version" ]]; then 147 | echo 148 | echo The java installation you have is not up to date 149 | echo $script_name requires at least version $required_version+, you have 150 | echo version $java_version 151 | echo 152 | echo Please go to http://www.java.com/getjava/ and download 153 | echo a valid Java Runtime and install before running $script_name. 154 | echo 155 | exit 1 156 | fi 157 | } 158 | 159 | 160 | run() { 161 | # no jar? download it. 162 | [[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || { 163 | # still no jar? uh-oh. 164 | echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar" 165 | exit 1 166 | } 167 | 168 | # process the combined args, then reset "$@" to the residuals 169 | process_args "$@" 170 | set -- "${residual_args[@]}" 171 | argumentCount=$# 172 | 173 | # TODO - java check should be configurable... 174 | checkJava "1.6" 175 | 176 | #If we're in cygwin, we should use the windows config, and terminal hacks 177 | if [[ "$CYGWIN_FLAG" == "true" ]]; then 178 | stty -icanon min 1 -echo > /dev/null 2>&1 179 | addJava "-Djline.terminal=jline.UnixTerminal" 180 | addJava "-Dsbt.cygwin=true" 181 | fi 182 | 183 | # run sbt 184 | execRunner "$java_cmd" \ 185 | ${SBT_OPTS:-$default_sbt_opts} \ 186 | $(get_mem_opts $sbt_mem) \ 187 | ${java_opts} \ 188 | ${java_args[@]} \ 189 | -jar "$sbt_jar" \ 190 | "${sbt_commands[@]}" \ 191 | "${residual_args[@]}" 192 | 193 | exit_code=$? 194 | 195 | # Clean up the terminal from cygwin hacks. 196 | if [[ "$CYGWIN_FLAG" == "true" ]]; then 197 | stty icanon echo > /dev/null 2>&1 198 | fi 199 | exit $exit_code 200 | } 201 | 202 | runAlternateBoot() { 203 | local bootpropsfile="$1" 204 | shift 205 | addJava "-Dsbt.boot.properties=$bootpropsfile" 206 | run $@ 207 | } 208 | -------------------------------------------------------------------------------- /bin/sbt-launch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inakata/ruby_scala/3f54cc6f80678e30a211fb1374280246f08182ed/bin/sbt-launch.jar -------------------------------------------------------------------------------- /bin/sbt.bat: -------------------------------------------------------------------------------- 1 | @REM SBT launcher script 2 | @REM 3 | @REM Envioronment: 4 | @REM JAVA_HOME - location of a JDK home dir (mandatory) 5 | @REM SBT_OPTS - JVM options (optional) 6 | @REM Configuration: 7 | @REM sbtconfig.txt found in the SBT_HOME. 8 | 9 | @REM ZOMG! We need delayed expansion to build up CFG_OPTS later 10 | @setlocal enabledelayedexpansion 11 | 12 | @echo off 13 | set SBT_HOME=%~dp0 14 | set ERROR_CODE=0 15 | 16 | rem FIRST we load the config file of extra options. 17 | set FN=%SBT_HOME%\..\conf\sbtconfig.txt 18 | set CFG_OPTS= 19 | FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%FN%") DO ( 20 | set DO_NOT_REUSE_ME=%%i 21 | rem ZOMG (Part #2) WE use !! here to delay the expansion of 22 | rem CFG_OPTS, otherwise it remains "" for this loop. 23 | set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME! 24 | ) 25 | 26 | rem We use the value of the JAVACMD environment variable if defined 27 | set _JAVACMD=%JAVACMD% 28 | 29 | if "%_JAVACMD%"=="" ( 30 | if not "%JAVA_HOME%"=="" ( 31 | if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe" 32 | ) 33 | ) 34 | 35 | if "%_JAVACMD%"=="" set _JAVACMD=java 36 | 37 | rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config. 38 | set _JAVA_OPTS=%JAVA_OPTS% 39 | if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS% 40 | 41 | :run 42 | 43 | "%_JAVACMD%" %_JAVA_OPTS% %SBT_OPTS% -cp "%SBT_HOME%sbt-launch.jar" xsbt.boot.Boot %* 44 | if ERRORLEVEL 1 goto error 45 | goto end 46 | 47 | :error 48 | set ERROR_CODE=1 49 | 50 | :end 51 | 52 | @endlocal 53 | 54 | exit /B %ERROR_CODE% 55 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | organization := "com.github.inakata" 2 | 3 | name := "ruby_scala" 4 | 5 | version := "0.0.1" 6 | 7 | scalaVersion := "2.10.3" 8 | 9 | scalacOptions ++= Seq("-deprecation","-unchecked", "-Yrangepos") 10 | 11 | initialCommands in console += { 12 | Iterator("com.github.inakata.ruby_scala._").map("import "+).mkString("\n") 13 | } 14 | -------------------------------------------------------------------------------- /heredoc.rb: -------------------------------------------------------------------------------- 1 | < "" 11 | case Some(a) => a.toString 12 | } 13 | def r1chain[T, U](p: Parser[T], q: Parser[U])(combiner: (T, U) => T): Parser[T] = p ~ rep(q) ^^ { 14 | case x ~ xs => xs.foldLeft(x){ case (a, b) => combiner(a, b) } 15 | } 16 | 17 | lazy val anySpace: Parser[String] = ((regex("""\s""".r) | Comment)*) ^^ { (_).mkString } 18 | lazy val anySpaceWithoutLT: Parser[String] = regex("""[ \t\f]*""".r) ~ ??(Comment) ^^ { case r~c => r+c } 19 | lazy val WS: Parser[String] = regex("""\s+""".r) 20 | lazy val ConstID: Parser[String] = anySpace~>regex("""[A-Z][a-zA-Z0-9_]*""".r) 21 | lazy val LocalID: Parser[String] = anySpace~>regex("""[a-z_][a-zA-Z0-9_]*""".r) 22 | lazy val MethodID: Parser[String] = anySpace~>regex("""m[a-zA-Z0-9_]*""".r) 23 | lazy val GlobalID: Parser[String] = anySpace~>regex("""\$[a-zA-Z_][a-zA-Z0-9_]*""".r) 24 | lazy val ClassID: Parser[String] = anySpace~>regex("""@@[a-zA-Z_][a-zA-Z0-9_]*""".r) 25 | lazy val InstanceID: Parser[String] = anySpace~>regex("""@[a-zA-Z_][a-zA-Z0-9_]*""".r) 26 | 27 | // 8.2 Program text 28 | lazy val SourceCharacter: Parser[String] = 29 | regex("""[\u0000-\u007f]""".r) 30 | // 8.3 Line terminators 31 | lazy val LineTerminator: Parser[String] = 32 | anySpaceWithoutLT~>regex("""\u000a|\u000d\u000a""".r) //^^ { case a => " EOL\n" } 33 | // 8.4 Whitespace 34 | lazy val Whitespace: Parser[String] = 35 | ("\u0009" | "\u000b" | "\u000c" | "\u000d" | "\u0020" ) | 36 | LineTerminatorEscapeSequence 37 | lazy val LineTerminatorEscapeSequence: Parser[String] = 38 | "\\" ~ LineTerminator ^^ { case s~l => " escaped-EOL\n" } 39 | 40 | lazy val IdentifierCharacter: Parser[String] = regex("""[a-zA-Z0-9_]""".r) 41 | lazy val UppercaseCharacter: Parser[String] = regex("""[A-Z]""".r) 42 | lazy val LowercaseCharacter: Parser[String] = regex("""[a-z]""".r) 43 | 44 | lazy val SingleQUOTE: Parser[String] = anySpace~>"'" 45 | lazy val MULT: Parser[String] = anySpace~>"*" 46 | lazy val DIV: Parser[String] = anySpace~>"/" 47 | lazy val LPAREN: Parser[String] = anySpace~>"(" 48 | lazy val RPAREN: Parser[String] = anySpace~>")" 49 | lazy val LBRACE: Parser[String] = anySpace~>"{" 50 | lazy val RBRACE: Parser[String] = anySpace~>"}" 51 | lazy val LBRACKET: Parser[String] = anySpace~>"[" 52 | lazy val RBRACKET: Parser[String] = anySpace~>"]" 53 | lazy val QUESTION: Parser[String] = anySpace~>"?" 54 | lazy val COMMA: Parser[String] = anySpace~>"," 55 | lazy val VerticalBAR: Parser[String] = anySpace~>"|" 56 | lazy val SEMICOLON: Parser[String] = anySpace~>";" 57 | lazy val COLON: Parser[String] = anySpace~>":" 58 | lazy val DoubleCOLON: Parser[String] = anySpace~>"::" 59 | lazy val PERIOD: Parser[String] = anySpace~>"." 60 | lazy val DoublePERIOD: Parser[String] = anySpace~>".." 61 | lazy val TriplePERIOD: Parser[String] = anySpace~>"..." 62 | lazy val AndOP: Parser[String] = anySpace~>"&&" 63 | lazy val OrOP: Parser[String] = anySpace~>"||" 64 | lazy val NotEQ: Parser[String] = anySpace~>"!=" 65 | lazy val NotOP: Parser[String] = anySpace~>"!" 66 | lazy val NotTILDE: Parser[String] = anySpace~>"!~" 67 | lazy val AMPERSAND: Parser[String] = anySpace~>"&" 68 | 69 | lazy val ArrayEQ: Parser[String] = anySpace~>"[]=" 70 | lazy val ArraySYM: Parser[String] = anySpace~>"[]" 71 | lazy val AndASSIGN: Parser[String] = anySpace~>"&&=" 72 | lazy val OrASSIGN: Parser[String] = anySpace~>"||=" 73 | lazy val HatASSIGN: Parser[String] = anySpace~>"^=" 74 | lazy val AmpersandASSIGN: Parser[String] = anySpace~>"&=" 75 | lazy val VerticalBarASSIGN: Parser[String] = anySpace~>"|=" 76 | lazy val LtLtASSIGN: Parser[String] = anySpace~>"<<=" 77 | lazy val GtGtASSIGN: Parser[String] = anySpace~>">>=" 78 | lazy val PlusASSIGN: Parser[String] = anySpace~>"+=" 79 | lazy val MinusASSIGN: Parser[String] = anySpace~>"-=" 80 | lazy val StarStarASSIGN: Parser[String] = anySpace~>"**=" 81 | lazy val StarASSIGN: Parser[String] = anySpace~>"*=" 82 | lazy val SlashASSIGN: Parser[String] = anySpace~>"/=" 83 | lazy val PercentASSIGN: Parser[String] = anySpace~>"%=" 84 | 85 | lazy val HAT: Parser[String] = anySpace~>"^" 86 | lazy val LtEqGT: Parser[String] = anySpace~>"<=>" 87 | lazy val TripleEQ: Parser[String] = anySpace~>"===" 88 | lazy val DoubleEQ: Parser[String] = anySpace~>"==" 89 | lazy val EqTILDE: Parser[String] = anySpace~>"=~" 90 | lazy val EqGT: Parser[String] = anySpace~>"=>" 91 | lazy val GtEQ: Parser[String] = anySpace~>">=" 92 | lazy val GtGT: Parser[String] = anySpace~>">>" 93 | lazy val GT: Parser[String] = anySpace~>">" 94 | lazy val LtLT: Parser[String] = anySpace~>"<<" 95 | lazy val LtEQ: Parser[String] = anySpace~>"<=" 96 | lazy val LT: Parser[String] = anySpace~>"<" 97 | lazy val EQUAL: Parser[String] = anySpace~>"=" 98 | lazy val PLUS: Parser[String] = anySpace~>"+" 99 | lazy val PlusAT: Parser[String] = anySpace~>"+@" 100 | lazy val MinusAT: Parser[String] = anySpace~>"-@" 101 | lazy val MINUS: Parser[String] = anySpace~>"-" 102 | lazy val StarSTAR: Parser[String] = anySpace~>"**" 103 | lazy val STAR: Parser[String] = anySpace~>"*" 104 | lazy val SLASH: Parser[String] = anySpace~>"/" 105 | lazy val PERCENT: Parser[String] = anySpace~>"%" 106 | lazy val TILDE: Parser[String] = anySpace~>"~" 107 | lazy val BackQUOTE: Parser[String] = anySpace~>"`" 108 | 109 | lazy val AND: Parser[String] = anySpace~>"and" 110 | lazy val OR: Parser[String] = anySpace~>"or" 111 | lazy val NOT: Parser[String] = anySpace~>"not" 112 | lazy val RETURN: Parser[String] = anySpace~>"return" 113 | lazy val BREAK: Parser[String] = anySpace~>"break" 114 | lazy val NEXT: Parser[String] = anySpace~>"next" 115 | lazy val SUPER: Parser[String] = anySpace~>"super" 116 | lazy val YIELD: Parser[String] = anySpace~>"yield" 117 | lazy val DO: Parser[String] = anySpace~>"do" 118 | lazy val END: Parser[String] = anySpace~>"end" 119 | lazy val LINE: Parser[String] = anySpace~>"__LINE__" 120 | lazy val ENCODING: Parser[String] = anySpace~>"__ENCODING__" 121 | lazy val FILE: Parser[String] = anySpace~>"__FILE__" 122 | lazy val UpBEGIN: Parser[String] = anySpace~>"BEGIN" 123 | lazy val UpEND: Parser[String] = anySpace~>"END" 124 | lazy val ALIAS: Parser[String] = anySpace~>"alias" 125 | lazy val BEGIN: Parser[String] = anySpace~>"begin" 126 | lazy val CASE: Parser[String] = anySpace~>"case" 127 | lazy val CLASS: Parser[String] = anySpace~>"class" 128 | lazy val DEF: Parser[String] = anySpace~>"def" 129 | lazy val DEFINED: Parser[String] = anySpace~>"defined?" 130 | lazy val ELSE: Parser[String] = anySpace~>"else" 131 | lazy val ELSIF: Parser[String] = anySpace~>"elsif" 132 | lazy val ENSURE: Parser[String] = anySpace~>"ensure" 133 | lazy val FOR: Parser[String] = anySpace~>"for" 134 | lazy val FALSE: Parser[String] = anySpace~>"false" 135 | lazy val IF: Parser[String] = anySpace~>"if" 136 | lazy val IN: Parser[String] = anySpace~>"in" 137 | lazy val MODULE: Parser[String] = anySpace~>"module" 138 | lazy val NIL: Parser[String] = anySpace~>"nil" 139 | lazy val REDO: Parser[String] = anySpace~>"redo" 140 | lazy val RESCUE: Parser[String] = anySpace~>"rescue" 141 | lazy val RETRY: Parser[String] = anySpace~>"retry" 142 | lazy val SELF: Parser[String] = anySpace~>"self" 143 | lazy val THEN: Parser[String] = anySpace~>"then" 144 | lazy val TRUE: Parser[String] = anySpace~>"true" 145 | lazy val UNDEF: Parser[String] = anySpace~>"undef" 146 | lazy val UNLESS: Parser[String] = anySpace~>"unless" 147 | lazy val UNTIL: Parser[String] = anySpace~>"until" 148 | lazy val WHEN: Parser[String] = anySpace~>"when" 149 | lazy val WHILE: Parser[String] = anySpace~>"while" 150 | 151 | // 10.1, 10.2, 152 | 153 | lazy val program: Parser[Any] = 154 | compoundStatement 155 | 156 | lazy val compoundStatement: Parser[String] = 157 | memo(??(statementList) <~ ??(separatorList)) 158 | 159 | lazy val statementList: Parser[String] = 160 | memo(rep1sep(statement, separatorList) ^^ { (_).mkString("", "\n", "") } ) 161 | 162 | lazy val separatorList: Parser[String] = 163 | ( separator+ ) ^^ { case e => ";" } 164 | 165 | lazy val separator: Parser[String] = 166 | LineTerminator | 167 | SEMICOLON 168 | 169 | 170 | // 11.1 171 | 172 | lazy val expression: Parser[String] = // notExpression | keywordAndExpression | keywordOrExpression 173 | memo(chainl1 ( notExpression, not(LineTerminator) ~ (AND | OR) ^^ { 174 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } )) 175 | 176 | lazy val notExpression: Parser[String] = memo( 177 | keywordNotExpression | 178 | NotOP ~ methodInvocationWithoutParentheses ^^ {case n~m => "!" + m } | 179 | methodInvocationWithoutParentheses | 180 | operatorExpression ) 181 | 182 | lazy val keywordNotExpression: Parser[String] = 183 | NOT ~ notExpression ^^ { case n~e => "(not " +e+ ")" } 184 | 185 | // 11.2.3 Logical AND expressions 186 | 187 | lazy val operatorAndExpression: Parser[String] = memo( 188 | chainl1 ( equalityExpression, not(LineTerminator) ~ AndOP ^^ { 189 | case n~o => (l: String, r: String) => "("+l+" "+o+" "+r+")" } )) 190 | 191 | // 11.2.4 Logical OR expressions 192 | 193 | lazy val operatorOrExpression: Parser[String] = memo( 194 | chainl1 ( operatorAndExpression, not(LineTerminator) ~ OrOP ^^ { 195 | case n~o => (l: String, r: String) => "("+l+" "+o+" "+r+")" } )) 196 | 197 | // 11.3.1 198 | 199 | lazy val primaryMethodInvocation: Parser[String] = memo( 200 | superWithOptionalArgument | 201 | MethodOnlyIdentifier | 202 | MethodIdentifier ~ block ^^ { case m~b => m + b } | 203 | MethodIdentifier ~ not(WS) ~ argumentWithParentheses ~ ??(block) ^^ { 204 | case m~n~a~b => m + a + b } ) 205 | 206 | lazy val MethodIdentifier: Parser[String] = 207 | MethodID | 208 | ConstantIdentifier | 209 | MethodOnlyIdentifier // not LocalVariableIdentifier 210 | 211 | lazy val methodName: Parser[String] = 212 | OperatorMethodName | 213 | MethodIdentifier | 214 | Keyword 215 | 216 | // lazy val indexing-method-invocation // in primaryExpression 217 | lazy val methodNameExceptConstant: Parser[String] = 218 | not(ConstID) ~ methodName ^^ { case n~m => m } 219 | 220 | lazy val methodInvocationWithoutParentheses: Parser[String] = memo( 221 | command ^^ { case c => "method-inv-without-par("+c+")" } | 222 | chainedCommandWithDoBlock ~ (PERIOD | DoubleCOLON) ~ methodName ~ argumentWithoutParentheses ^^ { 223 | case c~p~m~a => "method-inv-without-par("+c+p+m+" "+a+")" } | 224 | chainedCommandWithDoBlock ^^ { case c => "method-inv-without-par("+c+")" } | 225 | returnWithArgument | 226 | breakWithArgument | 227 | nextWithArgument ) 228 | 229 | lazy val command: Parser[String] = memo( 230 | superWithArgument | 231 | yieldWithArgument | 232 | MethodIdentifier ~ not(not(WS) ~ LPAREN) ~ argumentWithoutParentheses ^^ { 233 | case m~n~a => "command("+m+" "+a+")" } | // 234 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ methodName ~ not(not(WS) ~ LPAREN) ~ 235 | argumentWithoutParentheses ^^ { case p~n1~c~m~n2~a => "command("+p+c+m+" "+a+")" } ) 236 | 237 | lazy val chainedCommandWithDoBlock: Parser[String] = memo( 238 | r1chain ( commandWithDoBlock, chainedMethodInvocation ) { case (x, y) => "chained(" + x + y + ")" } ) 239 | 240 | lazy val chainedMethodInvocation: Parser[String] = 241 | (PERIOD | DoubleCOLON) ~ methodName ~ ??(argumentWithParentheses) ^^ { case p~m~a => p+m+a } 242 | 243 | lazy val commandWithDoBlock: Parser[String] = 244 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ methodName ~ 245 | argumentWithoutParentheses ~ doBlock ^^ { case p~n~c~m~a~d => "command-do("+p+c+m+" "+a+" "+d+")" } | 246 | MethodIdentifier ~ argumentWithoutParentheses ~ doBlock ^^ { 247 | case m~a~d => "command-do("+m+" "+a+" "+d+")" } | 248 | superWithArgumentAndDoBlock 249 | 250 | //11.3.2 Method arguments 251 | 252 | lazy val indexingArgumentList: Parser[String] = 253 | command | 254 | operatorExpressionList ~ not(LineTerminator) ~ COMMA ~ splattingArgument ^^ { 255 | case o~n~c~s => o+", "+s } | 256 | operatorExpressionList ~ ??( not(LineTerminator) ~ COMMA ^^ { case n~c => ", " } ) ^^ { 257 | case o~c => o+c } | 258 | associationList ~ ??( not(LineTerminator) ~ COMMA ^^ { case n~c => ", " } ) ^^ { case a~c => a+c } | 259 | splattingArgument 260 | 261 | lazy val splattingArgument: Parser[String] = 262 | STAR ~ operatorExpression ^^ { case s~o => "*"+o } 263 | 264 | lazy val operatorExpressionList: Parser[String] = memo( 265 | rep1sep(operatorExpression, not(LineTerminator) ~ COMMA) ^^ { (_).mkString("", ", ", "") } ) 266 | 267 | lazy val argumentWithParentheses: Parser[String] = not(WS) ~ parenthesesAndArgument ^^ { case n~p => p } 268 | 269 | lazy val parenthesesAndArgument: Parser[String] = 270 | LPAREN ~ RPAREN ^^ { case l~r => "( )" } | 271 | LPAREN ~ argumentList ~ RPAREN ^^ { case l~a~r => "("+a+")" } | 272 | LPAREN ~ operatorExpressionList ~ not(LineTerminator) ~ COMMA ~ chainedCommandWithDoBlock ~ RPAREN ^^ { 273 | case l~o~n~c~b~r => "("+o+","+b+")" } | 274 | LPAREN ~ chainedCommandWithDoBlock ~ RPAREN ^^ { case l~b~r => "("+b+")" } 275 | 276 | lazy val argumentWithoutParentheses: Parser[String] = 277 | not(LBRACE) ~ not(LineTerminator) ~ argumentList ^^ { case n1~n2~a => a } 278 | 279 | lazy val argumentList: Parser[String] = 280 | command | 281 | blockArgument | 282 | splattingArgument ~ ??( COMMA ~ blockArgument ^^ { case c~b => ", "+b } ) ^^ { case s~c => s+c } | 283 | operatorExpressionList ~ not(LineTerminator) ~ COMMA ~ associationList ~ 284 | ??( not(LineTerminator) ~ COMMA ~ splattingArgument ^^ { case n~c~s => ", "+s }) ~ 285 | ??( not(LineTerminator) ~ COMMA ~ blockArgument ^^ { case n~c~b => ", "+b } ) ^^ { 286 | case o~n~c~a~s~b => o+", "+a+s+b } | 287 | ( operatorExpressionList | associationList ) ~ 288 | ??( not(LineTerminator) ~ COMMA ~ splattingArgument ^^ { case n~c~s => ", "+s }) ~ 289 | ??( not(LineTerminator) ~ COMMA ~ blockArgument ^^ { case n~c~b => ", "+b } ) ^^ { 290 | case oa~s~a => oa+s+a } 291 | 292 | lazy val blockArgument: Parser[String] = 293 | AMPERSAND ~ operatorExpression ^^ { case a~o => "&"+o } 294 | 295 | // 11.3.3 Blocks 296 | 297 | lazy val block: Parser[String] = memo( braceBlock | doBlock ) 298 | 299 | lazy val braceBlock: Parser[String] = 300 | LBRACE ~ ??(blockParameter) ~ blockBody ~ RBRACE ^^ { case l~p~b~r => "{"+p+b+"}" } 301 | 302 | lazy val doBlock: Parser[String] = 303 | DO ~ ??(blockParameter) ~ blockBody ~ END ^^ { case d~p~b~e => " do "+p+b+" end" } 304 | 305 | lazy val blockParameter: Parser[String] = 306 | VerticalBAR ~ VerticalBAR ^^ { case v1~v2 => "| | " } | 307 | OrOP | 308 | VerticalBAR ~ blockParameterList ~ VerticalBAR ^^ { case v1~b~v2 => "|"+b+"| " } 309 | 310 | lazy val blockParameterList: Parser[String] = 311 | leftHandSide | 312 | multipleLeftHandSide 313 | 314 | lazy val blockBody: Parser[String] = 315 | compoundStatement 316 | 317 | // 11.3.4 The super expression 318 | 319 | lazy val superWithOptionalArgument: Parser[String] = 320 | SUPER ~ ??(not(WS) ~ argumentWithoutParentheses ^^ { case n~a => a } ) ~ 321 | ??(block) ^^ { case s~a~b => "(super "+a+b+")" } 322 | 323 | lazy val superWithArgument: Parser[String] = 324 | SUPER ~ argumentWithoutParentheses ^^ { case s~a => "(super "+a+")" } 325 | 326 | lazy val superWithArgumentAndDoBlock: Parser[String] = 327 | SUPER ~ argumentWithoutParentheses ~ doBlock ^^ { case s~a~b => "(super "+a+b+")" } 328 | 329 | // 11.3.5 The yield expression 330 | 331 | lazy val yieldWithOptionalArgument: Parser[String] = 332 | yieldWithParenthesesAndArgument | 333 | yieldWithParenthesesWithoutArgument | 334 | YIELD 335 | 336 | lazy val yieldWithParenthesesAndArgument: Parser[String] = 337 | YIELD ~ not(WS) ~ LPAREN ~ argumentList ~ RPAREN ^^ { case y~n~l~a~r => "yield ("+a+")" } 338 | 339 | lazy val yieldWithParenthesesWithoutArgument: Parser[String] = 340 | YIELD ~ not(WS) ~ LPAREN ~ RPAREN ^^ { case y~n~l~r => "yield ( )" } 341 | 342 | lazy val yieldWithArgument: Parser[String] = 343 | YIELD ~ argumentWithoutParentheses ^^ { case y~a => "(yield "+a+")" } 344 | 345 | 346 | // 11.4 Operator expressions, 11.4.1 347 | 348 | lazy val operatorExpression: Parser[String] = memo( 349 | assignmentExpression | 350 | definedWithoutParentheses | 351 | conditionalOperatorExpression // ^^ { case c => "op-exp("+c+")" } 352 | ) 353 | // 11.4.2 Assignments 354 | 355 | lazy val assignmentExpression: Parser[String] = 356 | singleAssignmentExpression | 357 | abbreviatedAssignmentExpression | 358 | assignmentWithRescueModifier 359 | 360 | lazy val assignmentStatement: Parser[String] = 361 | singleAssignmentStatement | 362 | abbreviatedAssignmentStatement | 363 | multipleAssignmentStatement 364 | 365 | // 11.4.2.2 Single assignments 366 | 367 | lazy val singleAssignmentExpression: Parser[String] = 368 | singleVariableAssignmentExpression | 369 | scopedConstantAssignmentExpression | 370 | singleIndexingAssignmentExpression | 371 | singleMethodAssignmentExpression 372 | 373 | lazy val singleAssignmentStatement: Parser[String] = 374 | singleVariableAssignmentStatement | 375 | scopedConstantAssignmentStatement | 376 | singleIndexingAssignmentStatement | 377 | singleMethodAssignmentStatement 378 | 379 | // 11.4.2.2.2 Single variable assignments 380 | 381 | lazy val singleVariableAssignmentStatement: Parser[String] = 382 | variable ~ not(LineTerminator) ~ EQUAL ~ methodInvocationWithoutParentheses ^^ { 383 | case v~n~e~m => "single-variable-st("+v+"="+m+")" } 384 | 385 | lazy val singleVariableAssignmentExpression: Parser[String] = 386 | variable ~ not(LineTerminator) ~ EQUAL ~ operatorExpression ^^ { 387 | case v~n~e~o => "single-variable-ex("+v+"="+o+")" } 388 | 389 | // 11.4.2.2.3 Scoped constant assignments 390 | 391 | lazy val scopedConstantAssignmentExpression: Parser[String] = 392 | primaryExpression ~ not(WS) ~ DoubleCOLON ~ ConstantIdentifier ~ not(LineTerminator) ~ 393 | EQUAL ~ operatorExpression ^^ { 394 | case p~n1~d~c~n2~e~o => "scoped-constant-ex("+p+"::"+c+"="+o+")" } | 395 | DoubleCOLON ~ ConstantIdentifier ~ not(LineTerminator) ~ EQUAL ~ operatorExpression ^^ { 396 | case d~c~n2~e~o => "scoped-constant-ex(::"+c+"="+o+")" } 397 | 398 | lazy val scopedConstantAssignmentStatement: Parser[String] = 399 | primaryExpression ~ not(WS) ~ DoubleCOLON ~ ConstantIdentifier ~ not(LineTerminator) ~ 400 | EQUAL ~ methodInvocationWithoutParentheses ^^ { 401 | case p~n1~d~c~n2~e~m => "scoped-constant-st("+p+"::"+c+"="+m+")" } | 402 | DoubleCOLON ~ ConstantIdentifier ~ not(LineTerminator) ~ EQUAL ~ methodInvocationWithoutParentheses ^^ { 403 | case d~c~n2~e~m => "scoped-constant-st(::"+c+"="+m+")" } 404 | 405 | // 11.4.2.2.4 Single indexing assignments 406 | 407 | lazy val singleIndexingAssignmentExpression: Parser[String] = 408 | primaryExpression ~ not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ~ not(LineTerminator) ~ 409 | EQUAL ~ operatorExpression ^^ { case p~n1~l~i~r~n2~e~o => "single-indexing-ex("+p+"["+i+"]="+o+")" } 410 | 411 | lazy val singleIndexingAssignmentStatement: Parser[String] = 412 | primaryExpression ~ not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ~ not(LineTerminator) ~ 413 | EQUAL ~ methodInvocationWithoutParentheses ^^ { 414 | case p~n1~l~i~r~n2~e~m => "single-indexing-st("+p+"["+i+"]="+m+")" } 415 | 416 | // 11.4.2.2.5 Single method assignments 417 | 418 | lazy val singleMethodAssignmentExpression: Parser[String] = 419 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ LocalVariableIdentifier ~ 420 | not(LineTerminator) ~ EQUAL ~ operatorExpression ^^ { 421 | case p~n1~d~l~n2~e~o => "single-method-ex("+p+d+l+"="+o+")" } | 422 | primaryExpression ~ not(LineTerminator) ~ PERIOD ~ ConstantIdentifier ~ not(LineTerminator) ~ 423 | EQUAL ~ operatorExpression ^^ { case pe~n1~p~c~n2~e~o => "single-method-ex("+pe+p+c+"="+o+")" } 424 | 425 | lazy val singleMethodAssignmentStatement: Parser[String] = 426 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ LocalVariableIdentifier ~ 427 | not(LineTerminator) ~ EQUAL ~ methodInvocationWithoutParentheses ^^ { 428 | case p~n1~d~l~n2~e~m => "single-method-st("+p+d+l+"="+m+")" } | 429 | primaryExpression ~ not(LineTerminator) ~ PERIOD ~ ConstantIdentifier ~ not(LineTerminator) ~ 430 | EQUAL ~ methodInvocationWithoutParentheses ^^ { 431 | case pe~n1~p~c~n2~e~m => "single-method-st("+pe+p+c+"="+m+")" } 432 | 433 | // 11.4.2.3 Abbreviated assignments 434 | 435 | lazy val abbreviatedAssignmentExpression: Parser[String] = 436 | abbreviatedVariableAssignmentExpression | 437 | abbreviatedIndexingAssignmentExpression | 438 | abbreviatedMethodAssignmentExpression 439 | 440 | lazy val abbreviatedAssignmentStatement: Parser[String] = 441 | abbreviatedVariableAssignmentStatement | 442 | abbreviatedIndexingAssignmentStatement | 443 | abbreviatedMethodAssignmentStatement 444 | 445 | // 11.4.2.3.2 Abbreviated variable assignments 446 | 447 | lazy val abbreviatedVariableAssignmentExpression: Parser[String] = 448 | variable ~ not(LineTerminator) ~ assignmentOperator ~ operatorExpression ^^ { 449 | case v~n~a~o => "abbreviated-variable-ex("+v+a+o+")" } 450 | 451 | lazy val abbreviatedVariableAssignmentStatement: Parser[String] = 452 | variable ~ not(LineTerminator) ~ assignmentOperator ~ methodInvocationWithoutParentheses ^^ { 453 | case v~n~a~m => "abbreviated-variable-st("+v+a+m+")" } 454 | 455 | // 11.4.2.3.3 Abbreviated indexing assignments 456 | 457 | lazy val abbreviatedIndexingAssignmentExpression: Parser[String] = 458 | primaryExpression ~ not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ~ not(LineTerminator) ~ 459 | assignmentOperator ~ operatorExpression ^^ { 460 | case p~n1~l~i~r~n2~a~o => "abbreviated-indexing-ex("+p+l+i+r+a+o+")" } 461 | 462 | lazy val abbreviatedIndexingAssignmentStatement: Parser[String] = 463 | primaryExpression ~ not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ~ not(LineTerminator) ~ 464 | assignmentOperator ~ methodInvocationWithoutParentheses ^^ { 465 | case p~n1~l~i~r~n2~a~m => "abbreviated-indexing-st("+p+l+i+r+a+m+")" } 466 | 467 | // 11.4.2.3.4 Abbreviated method assignments 468 | 469 | lazy val abbreviatedMethodAssignmentExpression: Parser[String] = 470 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ LocalVariableIdentifier ~ 471 | not(LineTerminator) ~ assignmentOperator ~ operatorExpression ^^ { 472 | case pe~n1~p~l~n2~a~o => "abbreviated-method-ex("+pe+p+l+a+o+")" } | 473 | primaryExpression ~ not(LineTerminator) ~ PERIOD ~ ConstantIdentifier ~ not(LineTerminator) ~ 474 | assignmentOperator ~ operatorExpression ^^ { 475 | case pe~n1~p~c~n2~a~o => "abbreviated-method-st("+pe+p+c+a+o+")" } 476 | 477 | lazy val abbreviatedMethodAssignmentStatement: Parser[String] = 478 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ LocalVariableIdentifier ~ 479 | not(LineTerminator) ~ assignmentOperator ~ methodInvocationWithoutParentheses ^^ { 480 | case pe~n1~p~l~n2~a~o => "abbreviated-method-st("+pe+p+l+a+o+")" } | 481 | primaryExpression ~ not(LineTerminator) ~ PERIOD ~ ConstantIdentifier ~ not(LineTerminator) ~ 482 | assignmentOperator ~ methodInvocationWithoutParentheses ^^ { 483 | case pe~n1~p~c~n2~a~m => "abbreviated-method-st("+pe+p+c+a+m+")" } 484 | 485 | lazy val assignmentOperator: Parser[String] = 486 | AndASSIGN | OrASSIGN | HatASSIGN | AmpersandASSIGN | VerticalBarASSIGN | LtLtASSIGN | GtGtASSIGN | 487 | PlusASSIGN | MinusASSIGN | StarStarASSIGN | StarASSIGN | SlashASSIGN | PercentASSIGN 488 | 489 | // 11.4.2.4 Multiple assignments 490 | 491 | lazy val multipleAssignmentStatement: Parser[String] = 492 | manyToOneAssignmentStatement | 493 | oneToPackingAssignmentStatement | 494 | manyToManyAssignmentStatement 495 | 496 | lazy val manyToOneAssignmentStatement: Parser[String] = 497 | leftHandSide ~ not(LineTerminator) ~ EQUAL ~ multipleRightHandSide ^^ { 498 | case l~n~e~m => "many-to-one-st("+l+"="+m+")" } 499 | 500 | lazy val oneToPackingAssignmentStatement: Parser[String] = 501 | packingLeftHandSide ~ not(LineTerminator) ~ 502 | EQUAL ~ ( methodInvocationWithoutParentheses | operatorExpression ) ^^ { 503 | case p~n~e~m => "one-to-packing-st("+p+"="+m+")" } 504 | 505 | lazy val manyToManyAssignmentStatement: Parser[String] = 506 | multipleLeftHandSide ~ not(LineTerminator) ~ EQUAL ~ multipleRightHandSide ^^ { 507 | case ml~n~e~mr => "many-to-many-st("+ml+"="+mr+")" } | 508 | multipleButNotPackingLeftHandSide ~ not(LineTerminator) ~ 509 | EQUAL ~ ( methodInvocationWithoutParentheses | operatorExpression ) ^^ { 510 | case ml~n~e~m => "many-to-many-st("+ml+"="+m+")" } 511 | 512 | lazy val multipleButNotPackingLeftHandSide: Parser[String] = 513 | not(packingLeftHandSide) ~ multipleLeftHandSide ^^ { case n~m => m } 514 | 515 | lazy val leftHandSide: Parser[String] = 516 | primaryExpression ~ not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ^^ { 517 | case p~n~l~i~r => p+"["+i+"]" } | 518 | primaryExpression ~ not(LineTerminator) ~ (PERIOD | DoubleCOLON) ~ 519 | ( LocalVariableIdentifier | ConstantIdentifier ) ^^ { case pe~n~p~i => pe+p+i } | 520 | DoubleCOLON ~ ConstantIdentifier ^^ { case d~c => "::"+c } | 521 | variable 522 | 523 | lazy val multipleLeftHandSide: Parser[String] = 524 | ((( multipleLeftHandSideItem ~ not(LineTerminator) ~ COMMA ^^ {case m~n~c => m+", "})+) ^^ { 525 | (_).mkString }) ~ ??(multipleLeftHandSideItem | packingLeftHandSide) ^^ { case s~m => s+m } | 526 | packingLeftHandSide | 527 | groupedLeftHandSide 528 | 529 | lazy val packingLeftHandSide: Parser[String] = 530 | STAR ~ ??(leftHandSide) ^^ { case s~l => s+l } 531 | 532 | lazy val groupedLeftHandSide: Parser[String] = 533 | LPAREN ~ multipleLeftHandSide ~ RPAREN ^^ { case l~m~r => "("+m+")" } 534 | 535 | lazy val multipleLeftHandSideItem: Parser[String] = 536 | leftHandSide | 537 | groupedLeftHandSide 538 | 539 | lazy val multipleRightHandSide: Parser[String] = 540 | operatorExpressionList ~ not(LineTerminator) ~ COMMA ~ splattingRightHandSide ^^ { 541 | case o~n~c~s => "multiple-right("+o+", "+s+")" } | 542 | operatorExpression ~ not(LineTerminator) ~ COMMA ~ operatorExpressionList ^^ { 543 | case o1~n~c~o2 => "multiple-right("+o1+", "+o2+")" } | 544 | splattingRightHandSide ^^ { case s => "multiple-right("+s+")" } 545 | 546 | lazy val splattingRightHandSide: Parser[String] = 547 | splattingArgument ^^ { case s => "splatting-right("+s+")" } 548 | 549 | // 11.4.2.5 Assignments with rescue modifiers 550 | 551 | lazy val assignmentWithRescueModifier: Parser[String] = 552 | leftHandSide ~ not(LineTerminator) ~ EQUAL ~ operatorExpression ~ not(LineTerminator) ~ 553 | RESCUE ~ operatorExpression ^^ { case l~n1~e~o1~n2~r~o2 => l+"="+o1+" rescue "+o2 } 554 | 555 | // 11.4.3 Unary operator expressions 556 | 557 | lazy val unaryMinusExpression: Parser[String] = 558 | powerExpression | 559 | MINUS ~ powerExpression ^^ { case m~p => "-"+p } 560 | 561 | lazy val unaryExpression: Parser[String] = 562 | primaryExpression | 563 | TILDE ~ unaryExpression ^^ { case t~u => "~"+u } | 564 | PLUS ~ unaryExpression ^^ { case p~u => "+"+u } | 565 | NotOP ~ unaryExpression ^^ { case n~u => "!"+u } 566 | 567 | // 11.4.3.2 The defined? expression 568 | 569 | lazy val definedWithParentheses: Parser[String] = 570 | DEFINED ~ LPAREN ~ expression ~ RPAREN ^^ { case d~l~e~r => "defind?("+e+")" } 571 | 572 | lazy val definedWithoutParentheses: Parser[String] = 573 | DEFINED ~ operatorExpression ^^ { case d~o => "defind?("+o+")" } 574 | 575 | // 11.4.4 Binary operator expressions 576 | 577 | lazy val equalityExpression: Parser[String] = memo( 578 | relationalExpression ~ ??(relationalOperation) ^^ { case e~r => e+r } ) 579 | 580 | lazy val relationalOperation: Parser[String] = 581 | not(LineTerminator) ~ relationalOperator ~ relationalExpression ^^ { case n~o~e => o+e } 582 | 583 | lazy val relationalOperator: Parser[String] = LtEqGT | DoubleEQ | TripleEQ | NotEQ | EqTILDE | NotTILDE 584 | 585 | lazy val relationalExpression: Parser[String] = 586 | chainl1 ( bitwiseOrExpression, not(LineTerminator) ~ (GT | GtEQ | LT | LtEQ) ^^ { 587 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } ) 588 | 589 | lazy val bitwiseOrExpression: Parser[String] = 590 | chainl1 ( bitwiseAndExpression, not(LineTerminator) ~ (VerticalBAR | HAT) ^^ { 591 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } ) 592 | 593 | lazy val bitwiseAndExpression: Parser[String] = 594 | chainl1 ( bitwiseShiftExpression, not(LineTerminator) ~ AMPERSAND ^^ { 595 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } ) 596 | 597 | lazy val bitwiseShiftExpression: Parser[String] = 598 | chainl1 ( additiveExpression, not(LineTerminator) ~ (LtLT | GtGT) ^^ { 599 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } ) 600 | 601 | lazy val additiveExpression: Parser[String] = 602 | chainl1 ( multiplicativeExpression, not(LineTerminator) ~ (PLUS | MINUS) ^^ { 603 | case n~op => (l: String, r: String) => "("+ l+" "+op+" "+r +")" } ) 604 | 605 | lazy val multiplicativeExpression: Parser[String] = 606 | chainl1 ( unaryMinusExpression, not(LineTerminator) ~ (MULT | DIV | PERCENT) ^^ { 607 | case n~op => (l: String, r:String) => "(" + l+op+r +")" }) 608 | 609 | lazy val powerExpression: Parser[String] = 610 | unaryExpression ~ not(LineTerminator) ~ StarSTAR ~ powerExpression ^^ { 611 | case u~n~s~p => "("+u+"**"+p+")" } | 612 | unaryExpression 613 | 614 | // 11.5 Primary expressions 615 | 616 | lazy val primaryExpression: Parser[String] = memo( 617 | r1chain ( primaryExpression1, 618 | not(WS) ~ DoubleCOLON ~ ConstID ^^ { case n~d~c => "::" + c } | //scoped-constant-reference 619 | not(LineTerminator) ~ PERIOD ~ methodName ~ not(argumentWithoutParentheses) ~ 620 | ??(argumentWithParentheses) ~ ??(block) ^^ { 621 | case n1~p~m~n2~a~b => "." + m + a + b } | //primary-method-invocation 622 | not(LineTerminator) ~ DoubleCOLON ~ methodName ~ argumentWithParentheses ~ ??(block) ^^ { 623 | case n~d~m~a~b => "::" + m + a + b } | //primary-method-invocation 624 | not(LineTerminator) ~ DoubleCOLON ~ methodNameExceptConstant ~ ??(block) ^^ { 625 | case n~d~m~b => "::" + m + b } | //primary-method-invocation 626 | not(WS) ~ LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ~ not(EQUAL) ^^ { 627 | case n1~l~i~r~n2 => "["+i+"]" } //indexing-method-invocation 628 | ) { case (x, y) => "(" + x + y + ")" } ) 629 | 630 | lazy val primaryExpression1: Parser[String] = 631 | classDefinition | 632 | singletonClassDefinition | 633 | moduleDefinition | 634 | methodDefinition | 635 | singletonMethodDefinition | 636 | yieldWithOptionalArgument | 637 | unlessExpression | 638 | caseExpression | 639 | whileExpression | 640 | untilExpression | 641 | forExpression | 642 | returnWithoutArgument | 643 | breakWithoutArgument | 644 | nextWithoutArgument | 645 | redoExpression | 646 | retryExpression | 647 | beginExpression | 648 | arrayConstructor | 649 | hashConstructor | 650 | definedWithParentheses | 651 | groupingExpression | 652 | scopedConstantReference | 653 | primaryMethodInvocation ^^ { case p => "primary-method-inv("+p+")" }| 654 | literal | 655 | variableReference 656 | 657 | // 11.5.2.2.2 The if expression 658 | 659 | lazy val ifExpression: Parser[String] = 660 | IF ~ expression ~ thenClause ~ (((elsifClause)*) ^^ { (_).mkString("", "\n", "") }) ~ 661 | ??(elseClause) ~ END ^^ { case i~ex~t~ei~el~en => "if "+ex+" "+t+" "+ei+"\n "+el+" end" } 662 | 663 | lazy val thenClause: Parser[String] = 664 | separator ~ compoundStatement ^^ { case s~c => s+c } | 665 | separator ~ THEN ~ compoundStatement ^^ { case s~t~c => s+" then "+c } 666 | 667 | lazy val elseClause: Parser[String] = 668 | ELSE ~ compoundStatement ^^ { case e~c => "else "+c } 669 | 670 | lazy val elsifClause: Parser[String] = 671 | ELSIF ~ expression ~ thenClause ^^ { case ei~e~t => "elsif "+e+t } 672 | 673 | // 11.5.2.2.3 The unless expression 674 | 675 | lazy val unlessExpression: Parser[String] = 676 | UNLESS ~ expression ~ thenClause ~ ??(elseClause) ~ END ^^ { 677 | case u~e~t~el~en => "unless "+e+t+el+" end" } 678 | 679 | // 11.5.2.2.4 The case expression 680 | 681 | lazy val caseExpression: Parser[String] = caseExpressionWithExpression | caseExpressionWithoutExpression 682 | 683 | lazy val caseExpressionWithExpression: Parser[String] = 684 | CASE ~ expression ~ ??(separatorList) ~ (((whenClause)+) ^^ { (_).mkString("", "\n", "") }) ~ 685 | ??(elseClause) ~ END ^^ { case c~ex~s~w~el~en => "case "+ex+s+w+el+" end" } 686 | 687 | lazy val caseExpressionWithoutExpression: Parser[String] = 688 | CASE ~ ??(separatorList) ~ (((whenClause)+) ^^ { (_).mkString("", "\n", "") }) ~ 689 | ??(elseClause) ~ END ^^ { case c~s~w~el~en => "case "+s+w+el+" end" } 690 | 691 | lazy val whenClause: Parser[String] = WHEN ~ whenArgument ~ thenClause ^^ { 692 | case w~a~t => "when "+a+t } 693 | 694 | lazy val whenArgument: Parser[String] = 695 | operatorExpressionList ~ ??(not(LineTerminator) ~ COMMA ~ splattingArgument ^^ { 696 | case n~c~s => ", "+s }) ^^ { case o~s => o+s } | 697 | splattingArgument 698 | 699 | // 11.5.2.2.5 Conditional operator expression 700 | 701 | lazy val conditionalOperatorExpression: Parser[String] = 702 | rangeExpression ~ not(LineTerminator) ~ QUESTION ~ operatorExpression ~ 703 | not(LineTerminator) ~ COLON ~ operatorExpression ^^ { 704 | case r~n1~q~o1~n2~c~o2 => "(" + r + "?" + o1 + ":" + o2 + ")" } | 705 | rangeExpression 706 | 707 | // 11.5.2.3.2 The while expression 708 | 709 | lazy val whileExpression: Parser[String] = 710 | WHILE ~ expression ~ doClause ~ END ^^ { case w~ex~d~en => "while "+ex+d+" end-while" } 711 | 712 | lazy val doClause: Parser[String] = 713 | separator ~ compoundStatement ^^ { case s~c => s+c } | 714 | not(LineTerminator) ~ DO ~ compoundStatement ^^ { case n~d~c => "do "+c } 715 | 716 | // 11.5.2.3.3 The until expression 717 | 718 | lazy val untilExpression: Parser[String] = UNTIL ~ expression ~ doClause ~ END ^^ { 719 | case u~ex~d~en => "until "+ex+d+" end-until" } 720 | 721 | // 11.5.2.3.4 The for expression 722 | lazy val forExpression: Parser[String] = 723 | FOR ~ forVariable ~ not(LineTerminator) ~ IN ~ expression ~ doClause ~ END ^^ { 724 | case f~v~n~i~ex~d~en => "for "+v+" in "+ex+d+" end-for" } 725 | 726 | lazy val forVariable: Parser[String] = leftHandSide | multipleLeftHandSide 727 | 728 | // 11.5.2.4.2 The return expression 729 | 730 | lazy val returnWithoutArgument: Parser[String] = RETURN 731 | 732 | lazy val returnWithArgument: Parser[String] = RETURN ~ jumpArgument ^^ {case r~j => "(return "+j+")" } 733 | 734 | lazy val jumpArgument: Parser[String] = not(LineTerminator) ~ argumentList ^^ { case n~a => a } 735 | 736 | // 11.5.2.4.3 The break expression 737 | 738 | lazy val breakWithoutArgument: Parser[String] = BREAK 739 | 740 | lazy val breakWithArgument: Parser[String] = BREAK ~ jumpArgument ^^ {case b~j => "(break "+j+")" } 741 | 742 | // 11.5.2.4.4 The next expression 743 | 744 | lazy val nextWithoutArgument: Parser[String] = NEXT 745 | 746 | lazy val nextWithArgument: Parser[String] = NEXT ~ jumpArgument ^^ {case n~j => "(next "+j+")" } 747 | 748 | // 11.5.2.4.5 The redo expression 749 | 750 | lazy val redoExpression: Parser[String] = REDO 751 | 752 | // 11.5.2.4.6 The retry expression 753 | 754 | lazy val retryExpression: Parser[String] = RETRY 755 | 756 | // 11.5.2.5 The begin expression 757 | 758 | lazy val beginExpression: Parser[String] = 759 | BEGIN ~ bodyStatement ~ END ^^ { case b~s~e => "begin "+s+" end-begin" } 760 | 761 | lazy val bodyStatement: Parser[String] = 762 | compoundStatement ~ (((rescueClause)*) ^^ { (_).mkString("", "\n", "") }) ~ ??(elseClause) ~ 763 | ??(ensureClause) ^^ { case c~r~el~en => c+r+el+en } 764 | 765 | lazy val rescueClause: Parser[String] = 766 | RESCUE ~ not(LineTerminator) ~ ??(exceptionClassList) ~ ??(exceptionVariableAssignment) ~ 767 | thenClause ^^ { case r~n~ec~ea~t => "rescue "+ec+ea+t } 768 | 769 | lazy val exceptionClassList: Parser[String] = 770 | operatorExpression | 771 | multipleRightHandSide 772 | 773 | lazy val exceptionVariableAssignment: Parser[String] = EqGT ~ leftHandSide ^^ { case e~l => "=>"+l } 774 | 775 | lazy val ensureClause: Parser[String] = ENSURE ~ compoundStatement ^^ { case e~c => "ensure "+c } 776 | 777 | // 11.5.3 Grouping expression 778 | 779 | lazy val groupingExpression: Parser[String] = LPAREN~>compoundStatement<~RPAREN 780 | 781 | // 11.5.4 Variable references 782 | 783 | lazy val variableReference: Parser[String] = variable | pseudoVariable 784 | 785 | lazy val variable: Parser[String] = 786 | ConstantIdentifier | 787 | GlobalVariableIdentifier | 788 | ClassVariableIdentifier | 789 | InstanceVariableIdentifier | 790 | LocalVariableIdentifier 791 | 792 | lazy val scopedConstantReference: Parser[String] = 793 | DoubleCOLON ~ ConstID ^^ { case d~c => "::"+c } // | 794 | // primaryExpression ~ not(WS) ~ DoubleCOLON ~ ConstID 795 | 796 | // 11.5.4.8 Pseudo variables 797 | 798 | lazy val pseudoVariable: Parser[String] = 799 | nilExpression | 800 | trueExpression | 801 | falseExpression | 802 | selfExpression 803 | 804 | // 11.5.4.8.2 The nil expression 805 | 806 | lazy val nilExpression: Parser[String] = NIL 807 | 808 | // 11.5.4.8.3 The true expression and the false expression 809 | 810 | lazy val trueExpression: Parser[String] = TRUE 811 | 812 | lazy val falseExpression: Parser[String] = FALSE 813 | 814 | // 11.5.4.8.4 The self expression 815 | 816 | lazy val selfExpression: Parser[String] = SELF 817 | 818 | // 11.5.5.1 Array constructor 819 | 820 | lazy val arrayConstructor: Parser[String] = 821 | LBRACKET ~ ??(indexingArgumentList) ~ RBRACKET ^^ { case l~i~r => "["+i+"]" } 822 | 823 | // 11.5.5.2 Hash constructor 824 | 825 | lazy val hashConstructor: Parser[String] = 826 | LBRACE ~ ??(associationList ~ not(LineTerminator) ~ ??(COMMA) ^^ { case a~n~c => a+c } ) ~ 827 | RBRACE ^^ { case l~a~r => "{"+a+"}" } 828 | 829 | lazy val associationList: Parser[String] = 830 | rep1sep ( association, not(LineTerminator) ~ COMMA ) ^^ { (_).mkString("", ", ", "") } 831 | 832 | lazy val association: Parser[String] = 833 | associationKey ~ not(LineTerminator) ~ EqGT ~ associationValue ^^ { 834 | case k~n~e~v => k+"=>"+v } 835 | 836 | lazy val associationKey: Parser[String] = operatorExpression 837 | 838 | lazy val associationValue: Parser[String] = operatorExpression 839 | 840 | // 11.5.5.3 Range expression 841 | 842 | lazy val rangeExpression: Parser[String] = 843 | operatorOrExpression ~ not(LineTerminator) ~ rangeOperator ~ operatorOrExpression ^^ { 844 | case o1~n~r~o2 => o1 + r + o2 } | 845 | operatorOrExpression 846 | 847 | lazy val rangeOperator: Parser[String] = 848 | DoublePERIOD | 849 | TriplePERIOD 850 | 851 | // 12 Statements 852 | 853 | lazy val statement: Parser[String] = memo( 854 | r1chain ( statement1, 855 | not(LineTerminator) ~ IF ~ expression ^^ { case n~i~e => " if "+e } | // 12.3 The if modifier statement 856 | not(LineTerminator) ~ UNLESS ~ expression ^^ { case n~u~e => " unless "+e } | // 12.4 unless modifier 857 | not(LineTerminator) ~ WHILE ~ expression ^^ { case n~w~e => " while "+e } | // 12.5 while modifier 858 | not(LineTerminator) ~ UNTIL ~ expression ^^ { case n~u~e => " until "+e } | // 12.6 until modifier 859 | not(LineTerminator) ~ RESCUE ~ fallbackStatement ^^ { case n~r~f => " rescue "+f } // 12.7 rescue modifier 860 | ) { case (x, y) => "(" + x + y + ")" } ) 861 | 862 | lazy val fallbackStatement: Parser[String] = 863 | statement1 // not(keywordAndExpression) ~ not(keywordOrExpression) 864 | 865 | lazy val statement1: Parser[String] = 866 | assignmentStatement | 867 | expressionStatement | 868 | aliasStatement | 869 | undefStatement 870 | 871 | // 12.2 Expression statement 872 | 873 | lazy val expressionStatement: Parser[String] = expression 874 | 875 | // 13.1.2 Module definition 876 | 877 | lazy val moduleDefinition: Parser[String] = 878 | MODULE ~ modulePath ~ moduleBody ~ END ^^ { case m~p~b~e => "module "+p+b+"\nend-module" } 879 | 880 | lazy val modulePath: Parser[String] = topModulePath | moduleName | nestedModulePath 881 | 882 | lazy val moduleName: Parser[String] = ConstantIdentifier 883 | 884 | lazy val topModulePath: Parser[String] = DoubleCOLON ~ moduleName ^^ { case d~m => "::"+m } 885 | 886 | lazy val nestedModulePath: Parser[String] = 887 | primaryExpression ~ not(LineTerminator) ~ DoubleCOLON ~ moduleName ^^ { case p~n~d~m => p+"::"+m } 888 | 889 | lazy val moduleBody: Parser[String] = bodyStatement 890 | 891 | // 13.2.2 Class definition 892 | 893 | lazy val classDefinition: Parser[String] = 894 | CLASS ~ classPath ~ ??( not(LineTerminator) ~ LT ~ superclass ^^ { case n~l~s => "< "+s } ) ~ 895 | separator ~ classBody ~ END ^^ { case c~p~su~sep~b~e => "class "+p+su+sep+b+"\nend-class" } 896 | 897 | lazy val classPath: Parser[String] = 898 | topClassPath | 899 | className | 900 | nestedClassPath 901 | 902 | lazy val className: Parser[String] = 903 | ConstantIdentifier 904 | 905 | lazy val topClassPath: Parser[String] = 906 | DoubleCOLON ~ className ^^ { case d~c => "::"+c } 907 | 908 | lazy val nestedClassPath: Parser[String] = 909 | primaryExpression ~ not(LineTerminator) ~ DoubleCOLON ~ className ^^ { case p~n~d~m => p+"::"+m } 910 | 911 | lazy val superclass: Parser[String] = 912 | expression 913 | 914 | lazy val classBody: Parser[String] = 915 | bodyStatement 916 | 917 | // 13.3.1 Method definition 918 | 919 | lazy val methodDefinition: Parser[String] = 920 | DEF ~ definedMethodName ~ ( not(LineTerminator) ~ methodParameterPart ^^ { case n~m => m } | 921 | separator ^^ { case s => "; " } ) ~ methodBody ~ END ^^ { 922 | case d~na~p~b~e => "def "+na+p+b+" end-def" } 923 | 924 | lazy val definedMethodName: Parser[String] = 925 | methodName | 926 | AssignmentLikeMethodIdentifier 927 | 928 | lazy val methodBody: Parser[String] = 929 | bodyStatement 930 | 931 | // 13.3.2 Method parameters 932 | 933 | lazy val methodParameterPart: Parser[String] = 934 | LPAREN ~ ??(parameterList) ~ RPAREN ^^ { case l~p~r => "("+p+")" } | 935 | parameterList ~ separator ^^ { case p~s => p+"; " } 936 | 937 | lazy val parameterList: Parser[String] = 938 | mandatoryParameterList ~ ??( COMMA ~ optionalParameterList ^^ { case c~p => ", "+p } ) ~ 939 | ??( COMMA ~ arrayParameter ^^ { case c~p => ", "+p } ) ~ ??( COMMA ~ procParameter ^^ { 940 | case c~p => ", "+p } ) ^^ { case m~o~a~p => m+o+a+p } | 941 | optionalParameterList ~ ??( COMMA ~ arrayParameter ^^ { case c~p => ", "+p } ) ~ 942 | ??( COMMA ~ procParameter ^^ { case c~p => ", "+p } ) ^^ { case o~a~p => o+a+p } | 943 | arrayParameter ~ ??( COMMA ~ procParameter ^^ { case c~p => ", "+p } ) ^^ { case a~p => a+p } | 944 | procParameter 945 | 946 | lazy val mandatoryParameterList: Parser[String] = 947 | rep1sep(mandatoryParameter, COMMA) ^^ { (_).mkString("", ", ", "") } 948 | 949 | lazy val mandatoryParameter: Parser[String] = 950 | LocalVariableIdentifier 951 | 952 | lazy val optionalParameterList: Parser[String] = 953 | rep1sep(optionalParameter, COMMA) ^^ { (_).mkString("", ", ", "") } 954 | 955 | lazy val optionalParameter: Parser[String] = 956 | optionalParameterName ~ EQUAL ~ defaultParameterExpression ^^ { case o~e~d => o+"="+d } 957 | 958 | lazy val optionalParameterName: Parser[String] = 959 | LocalVariableIdentifier 960 | 961 | lazy val defaultParameterExpression: Parser[String] = 962 | operatorExpression 963 | 964 | lazy val arrayParameter: Parser[String] = 965 | STAR ~ arrayParameterName ^^ { case s~a => "*"+a } | 966 | STAR 967 | 968 | lazy val arrayParameterName: Parser[String] = 969 | LocalVariableIdentifier 970 | 971 | lazy val procParameter: Parser[String] = 972 | AMPERSAND ~ procParameterName ^^ { case a~p => "&"+p } 973 | 974 | lazy val procParameterName: Parser[String] = 975 | LocalVariableIdentifier 976 | 977 | // 13.3.6 The alias statement 978 | 979 | lazy val aliasStatement: Parser[String] = 980 | ALIAS ~ newName ~ aliasedName ^^ { case a~nn~an => "alias("+nn+", "+an+")" } 981 | 982 | lazy val newName: Parser[String] = 983 | methodNameOrSymbol 984 | 985 | lazy val aliasedName: Parser[String] = 986 | methodNameOrSymbol 987 | 988 | lazy val methodNameOrSymbol: Parser[String] = 989 | definedMethodName | 990 | Symbol 991 | 992 | // 13.3.7 The undef statement 993 | 994 | lazy val undefStatement: Parser[String] = 995 | UNDEF ~ undefList ^^ { case u~l => "undef("+l+")" } 996 | 997 | lazy val undefList: Parser[String] = 998 | rep1sep(methodNameOrSymbol, COMMA) ^^ { (_).mkString("", ", ", "") } 999 | 1000 | // 13.4.2 Singleton class definition 1001 | 1002 | lazy val singletonClassDefinition: Parser[String] = 1003 | CLASS ~ LtLT ~ expression ~ separator ~ singletonClassBody ~ END ^^ { 1004 | case c~l~ex~s~b~en => "class << "+ex+s+b+"\nend-s-class" } 1005 | lazy val singletonClassBody: Parser[String] = 1006 | bodyStatement 1007 | 1008 | // 13.4.3 Singleton method definition 1009 | 1010 | lazy val singletonMethodDefinition: Parser[String] = 1011 | DEF ~ singletonObject ~ (PERIOD | DoubleCOLON) ~ definedMethodName ~ 1012 | ( not(LineTerminator) ~ methodParameterPart ^^ { case n~m => m } | 1013 | separator ^^ { case s => ";" } ) ~ methodBody ~ END ^^ { 1014 | case d~s~pc~dn~p~b~e => "def "+s+pc+dn+p+b+" end-def" } 1015 | 1016 | lazy val singletonObject: Parser[String] = 1017 | variableReference | 1018 | LPAREN ~ expression ~ RPAREN ^^ { case l~e~r => "("+e+")" } 1019 | 1020 | // 8.5 Comments 1021 | 1022 | lazy val Comment: Parser[String] = 1023 | SingleLineComment | 1024 | MultiLineComment 1025 | 1026 | lazy val SingleLineComment: Parser[String] = 1027 | regex("""#""".r) ~ CommentContent ^^ { case s~c => s+c } 1028 | 1029 | lazy val CommentContent: Parser[String] = 1030 | LineContent 1031 | 1032 | lazy val LineContent: Parser[String] = 1033 | (( not(LineTerminator) ~ SourceCharacter ^^ { case n~s => s } )*) ^^ { (_).mkString } 1034 | 1035 | lazy val MultiLineComment: Parser[String] = 1036 | MultiLineCommentBeginLine ~ ((MultiLineCommentLine*) ^^ { (_).mkString } ) ~ 1037 | MultiLineCommentEndLine ^^ { case b~c~e => b+c+e } 1038 | 1039 | lazy val MultiLineCommentBeginLine: Parser[String] = 1040 | regex("""^=begin""".r) ~ ??(RestOfBeginEndLine) ~ LineTerminator ^^ { case b~r~l => b+r+l } 1041 | 1042 | lazy val MultiLineCommentEndLine: Parser[String] = 1043 | regex("""^=end""".r) ~ ??(RestOfBeginEndLine) ~ ( LineTerminator | regex("""\z""".r) ) ^^ { 1044 | case e~r~l => e+r+"\n" } 1045 | lazy val RestOfBeginEndLine: Parser[String] = 1046 | (((not(LineTerminatorEscapeSequence) ~ Whitespace ^^ { case n~w => w })+) ^^ { 1047 | (_).mkString } ) ~ CommentContent ^^ { case w~c => w+c } 1048 | 1049 | lazy val MultiLineCommentLine: Parser[String] = 1050 | not(MultiLineCommentEndLine) ~ CommentLine ^^ { case n~c => c } 1051 | 1052 | lazy val CommentLine: Parser[String] = 1053 | CommentContent ~ LineTerminator ^^ { case c~l => c+"\n" } 1054 | 1055 | // 8.7.2 Keywords 1056 | 1057 | lazy val Keyword: Parser[String] = 1058 | KeywordString ~ not(IdentifierCharacter) ^^ { case k~n => k } 1059 | 1060 | lazy val KeywordString: Parser[String] = 1061 | LINE | ENCODING | FILE | UpBEGIN | UpEND | ALIAS | AND | BEGIN | BREAK | 1062 | CASE | CLASS | DEF | DEFINED | DO | ELSE | ELSIF | END | ENSURE | FOR | FALSE | IF | IN | 1063 | MODULE | NEXT | NIL | NOT | OR | REDO | RESCUE | RETRY | RETURN | SELF | SUPER | THEN | 1064 | TRUE | UNDEF | UNLESS | UNTIL | WHEN | WHILE | YIELD 1065 | 1066 | // 8.7.3 Identifiers 1067 | 1068 | lazy val LocalVariableIdentifier: Parser[String] = 1069 | not(Keyword) ~ not(MethodID) ~ LocalID ^^ { case n1~n2~l => l } 1070 | 1071 | lazy val GlobalVariableIdentifier: Parser[String] = 1072 | GlobalID 1073 | 1074 | lazy val ClassVariableIdentifier: Parser[String] = 1075 | ClassID 1076 | 1077 | lazy val InstanceVariableIdentifier: Parser[String] = 1078 | InstanceID 1079 | 1080 | lazy val ConstantIdentifier: Parser[String] = 1081 | ConstID 1082 | 1083 | lazy val MethodOnlyIdentifier: Parser[String] = 1084 | (LocalID | ConstID) ~ (NotOP | QUESTION) ^^ { case i~q => i+q } 1085 | 1086 | lazy val AssignmentLikeMethodIdentifier: Parser[String] = 1087 | ( ConstantIdentifier | LocalVariableIdentifier ) ~ EQUAL ^^ { case i~e => i+"=" } 1088 | 1089 | 1090 | lazy val OperatorMethodName: Parser[String] = 1091 | HAT | AMPERSAND | VerticalBAR | EQUAL | DoubleEQ | TripleEQ | EqTILDE | GT | GtEQ | 1092 | LT | LtEQ | LtLT | GtGT | PLUS | MINUS | STAR | SLASH | PERCENT | StarSTAR | 1093 | TILDE | PlusAT | MinusAT | ArrayEQ | ArraySYM | BackQUOTE 1094 | 1095 | // 8.7.6 Literals 1096 | 1097 | lazy val literal: Parser[String] = 1098 | anySpace~>literalString 1099 | 1100 | lazy val literalString: Parser[String] = 1101 | NumericLiteral | 1102 | StringLiteral | 1103 | ArrayLiteral | 1104 | RegularExpressionLiteral | 1105 | Symbol 1106 | 1107 | // 8.7.6.2 Numeric literals 1108 | 1109 | lazy val NumericLiteral: Parser[String] = SignedNumber | UnsignedNumber 1110 | 1111 | lazy val SignedNumber: Parser[String] = regex("""\+|\-""".r) ~ UnsignedNumber ^^ { case r~u => r+u } 1112 | 1113 | lazy val UnsignedNumber: Parser[String] = 1114 | FloatLiteral | 1115 | IntegerLiteral 1116 | 1117 | lazy val IntegerLiteral: Parser[String] = 1118 | DecimalIntegerLiteral | 1119 | BinaryIntegerLiteral | 1120 | OctalIntegerLiteral | 1121 | HexadecimalIntegerLiteral 1122 | 1123 | lazy val DecimalIntegerLiteral: Parser[String] = 1124 | UnprefixedDecimalIntegerLiteral | 1125 | PrefixedDecimalIntegerLiteral 1126 | 1127 | lazy val UnprefixedDecimalIntegerLiteral: Parser[String] = 1128 | regex("""0""".r) | 1129 | DecimalDigitExceptZero ~ ((( ??(regex("""_""".r)) ~ DecimalDigit ^^ { case r~d => r+d } )*) ^^ { 1130 | (_).mkString } ) ^^ { case d~r => d+r } 1131 | 1132 | lazy val PrefixedDecimalIntegerLiteral: Parser[String] = 1133 | regex("""0(d|D)""".r) ~ DigitDecimalPart ^^ { case r~d => r+d } 1134 | 1135 | lazy val DigitDecimalPart: Parser[String] = 1136 | DecimalDigit ~ ((( ??(regex("""_""".r)) ~ DecimalDigit ^^ { case r~d => r+d } )*) ^^ { 1137 | (_).mkString } ) ^^ { case d~r => d+r } 1138 | 1139 | lazy val BinaryIntegerLiteral: Parser[String] = 1140 | regex("""0(b|B)""".r) ~ BinaryDigit ~ ((( ??(regex("""_""".r)) ~ BinaryDigit ^^ { 1141 | case r~b => r+b } )*) ^^ { (_).mkString } ) ^^ { case r~b1~b2 => r+b1+b2 } 1142 | 1143 | lazy val OctalIntegerLiteral: Parser[String] = 1144 | regex("""0(_|o|O)""".r) ~ OctalDigit ~ ((( ??(regex("""_""".r)) ~ OctalDigit ^^ { 1145 | case r~o => r+o } )*) ^^ { (_).mkString } ) ^^ { case r~o1~o2 => r+o1+o2 } 1146 | 1147 | lazy val HexadecimalIntegerLiteral: Parser[String] = 1148 | regex("""0(x|X)""".r) ~ HexadecimalDigit ~ ((( ??(regex("""_""".r)) ~ HexadecimalDigit ^^ { 1149 | case r~x => r+x } )*) ^^ { (_).mkString } ) ^^ { case r~x1~x2 => r+x1+x2 } 1150 | 1151 | lazy val FloatLiteral: Parser[String] = FloatLiteralWithExponent | FloatLiteralWithoutExponent 1152 | 1153 | lazy val FloatLiteralWithoutExponent: Parser[String] = 1154 | UnprefixedDecimalIntegerLiteral ~ regex("""\.""".r) ~ DigitDecimalPart ^^ { case u~r~d => u+"."+d } 1155 | 1156 | lazy val FloatLiteralWithExponent: Parser[String] = 1157 | SignificandPart ~ ExponentPart ^^ { case s~e => s+e } 1158 | 1159 | lazy val SignificandPart: Parser[String] = FloatLiteralWithoutExponent | UnprefixedDecimalIntegerLiteral 1160 | 1161 | lazy val ExponentPart: Parser[String] = regex("""(e|E)(\+|\-)?""".r) ~ DigitDecimalPart ^^ { case e~d => e+d } 1162 | 1163 | lazy val DecimalDigit: Parser[String] = regex("""[0-9]""".r) 1164 | 1165 | lazy val DecimalDigitExceptZero: Parser[String] = regex("""[1-9]""".r) 1166 | 1167 | lazy val BinaryDigit: Parser[String] = regex("""0|1""".r) 1168 | 1169 | lazy val OctalDigit: Parser[String] = regex("""[0-7]""".r) 1170 | 1171 | lazy val HexadecimalDigit: Parser[String] = DecimalDigit | regex("""[a-fA-F]""".r) 1172 | 1173 | // 8.7.6.3 String literals 1174 | 1175 | lazy val StringLiteral: Parser[String] = 1176 | SingleQuotedString | 1177 | DoubleQuotedString | 1178 | QuotedNonExpandedLiteralString | 1179 | QuotedExpandedLiteralString | 1180 | HereDocument | 1181 | ExternalCommandExecution 1182 | 1183 | // 8.7.6.3.2 Single quoted strings 1184 | 1185 | lazy val SingleQuotedString: Parser[String] = 1186 | regex("""'""".r) ~ ((SingleQuotedStringCharacter*) ^^ { (_).mkString } ) ~ regex("""'""".r) ^^ { 1187 | case r1~s~r2 => "'"+s+"'" } 1188 | 1189 | lazy val SingleQuotedStringCharacter: Parser[String] = 1190 | SingleQuotedStringNonEscapedCharacter | 1191 | SingleQuotedEscapeSequence 1192 | 1193 | lazy val SingleQuotedEscapeSequence: Parser[String] = 1194 | SingleEscapeCharacterSequence | 1195 | SingleQuotedStringNonEscapedCharacterSequence 1196 | 1197 | lazy val SingleEscapeCharacterSequence: Parser[String] = 1198 | regex("""\\""".r) ~ SingleQuotedStringMetaCharacter ^^ { case r~s => "\\"+s } 1199 | 1200 | lazy val SingleQuotedStringNonEscapedCharacterSequence: Parser[String] = 1201 | regex("""\\""".r) ~ SingleQuotedStringNonEscapedCharacter ^^ { case r~s => "\\"+s } 1202 | 1203 | lazy val SingleQuotedStringMetaCharacter: Parser[String] = 1204 | regex("""'|\\""".r) 1205 | 1206 | lazy val SingleQuotedStringNonEscapedCharacter: Parser[String] = 1207 | not(SingleQuotedStringMetaCharacter) ~ SourceCharacter ^^ { case n~s => s } 1208 | 1209 | // 8.7.6.3.3 Double quoted strings 1210 | 1211 | lazy val DoubleQuotedString: Parser[String] = 1212 | regex(""""""".r) ~ ((DoubleQuotedStringCharacter*) ^^ { (_).mkString } ) ~ regex(""""""".r) ^^ { 1213 | case r1~s~r2 => "\""+s+"\"" } 1214 | 1215 | lazy val DoubleQuotedStringCharacter: Parser[String] = 1216 | not(regex(""""|#|\\""".r)) ~ SourceCharacter ^^ { case n~s => s } | 1217 | regex("""#""".r) ~ not(LookaheadCharacter) ^^ { case r~n => "#" } | 1218 | DoubleEscapeSequence | 1219 | InterpolatedCharacterSequence 1220 | 1221 | lazy val LookaheadCharacter: Parser[String] = 1222 | regex("""\$|@|\{""".r) 1223 | 1224 | lazy val DoubleEscapeSequence: Parser[String] = 1225 | SimpleEscapeSequence | 1226 | NonEscapedSequence | 1227 | LineTerminatorEscapeSequence | 1228 | OctalEscapeSequence | 1229 | HexadecimalEscapeSequence | 1230 | ControlEscapeSequence 1231 | 1232 | lazy val SimpleEscapeSequence: Parser[String] = 1233 | regex("""\\""".r) ~ DoubleEscapedCharacter ^^ { case r~d => "\\"+d } 1234 | 1235 | lazy val DoubleEscapedCharacter: Parser[String] = 1236 | regex("""n|t|r|f|v|a|e|b|s""".r) 1237 | 1238 | lazy val NonEscapedSequence: Parser[String] = 1239 | regex("""\\""".r) ~ NonEscapedDoubleQuotedStringCharacter ^^ { case r~n => "\\"+n } 1240 | 1241 | lazy val NonEscapedDoubleQuotedStringCharacter: Parser[String] = 1242 | not( AlphaNumericCharacter | LineTerminator ) ~ SourceCharacter ^^ { case n~s => s } 1243 | 1244 | lazy val OctalEscapeSequence: Parser[String] = 1245 | regex("""\\""".r) ~ OctalDigit ~ ??(OctalDigit) ~ ??(OctalDigit) ^^ { 1246 | case r~o1~o2~o3 => "\\"+o1+o2+o3 } 1247 | 1248 | lazy val HexadecimalEscapeSequence: Parser[String] = 1249 | regex("""\\x""".r) ~ HexadecimalDigit ~ ??(HexadecimalDigit) ^^ { case r~h1~h2 => "\\x"+h1+h2 } 1250 | 1251 | lazy val ControlEscapeSequence: Parser[String] = 1252 | regex("""\\(C\-|c)""".r) ~ ControlEscapeCharacter ^^ { case r~c => r+c } 1253 | 1254 | lazy val ControlEscapeCharacter: Parser[String] = 1255 | DoubleEscapeSequence | 1256 | regex("""\?""".r) | 1257 | not( regex("""\\|\?""".r) ) ~ SourceCharacter ^^ { case n~s => s } 1258 | 1259 | lazy val InterpolatedCharacterSequence: Parser[String] = 1260 | regex("""#""".r) ~ GlobalVariableIdentifier ^^ { case r~i => "#"+i } | 1261 | regex("""#""".r) ~ ClassVariableIdentifier ^^ { case r~i => "#"+i } | 1262 | regex("""#""".r) ~ InstanceVariableIdentifier ^^ { case r~i => "#"+i } | 1263 | regex("""#\{""".r) ~ compoundStatement ~ regex("""\}""".r) ^^ { case r1~s~r2 => "#{"+s+"}" } 1264 | 1265 | lazy val AlphaNumericCharacter: Parser[String] = 1266 | UppercaseCharacter | 1267 | LowercaseCharacter | 1268 | DecimalDigit 1269 | 1270 | // 8.7.6.3.4 Quoted non-expanded literal strings 1271 | 1272 | lazy val QuotedNonExpandedLiteralString: Parser[String] = 1273 | regex("""%q""".r) ~ NonExpandedDelimitedString ^^ { case r~n => "%q"+n } 1274 | lazy val NonExpandedDelimitedString: Parser[String] = 1275 | LiteralBeginningDelimiter >> { 1276 | case literalBegin => ( (NonExpandedLiteralString(literalBegin)*) ^^ { (_).mkString } ) ~ 1277 | LiteralEndingDelimiter2(literalBegin) ^^ { case s~e => literalBegin+s+e } } 1278 | 1279 | def NonExpandedLiteralString(literalBegin: String): Parser[String] = 1280 | (if (literalBegin == "{" || literalBegin == "(" || literalBegin == "[" || literalBegin == "<" ) 1281 | NonExpandedDelimitedString2(literalBegin) else failure("not matched") ) | 1282 | NonExpandedLiteralCharacter(literalBegin) 1283 | 1284 | def NonExpandedDelimitedString2(literalBegin: String): Parser[String] = 1285 | LiteralBeginningDelimiter2(literalBegin) ~ ((NonExpandedLiteralString(literalBegin)*) ^^ { 1286 | (_).mkString } ) ~ LiteralEndingDelimiter2(literalBegin) ^^ { case b~s~e => b+s+e } 1287 | 1288 | def NonExpandedLiteralCharacter(literalBegin: String): Parser[String] = 1289 | NonEscapedLiteralCharacter(literalBegin) | 1290 | NonExpandedLiteralEscapeSequence(literalBegin) 1291 | 1292 | def NonEscapedLiteralCharacter(literalBegin: String): Parser[String] = 1293 | not(QuotedLiteralEscapeCharacter(literalBegin)) ~ SourceCharacter ^^ { case n~s => s } 1294 | 1295 | def NonExpandedLiteralEscapeSequence(literalBegin: String): Parser[String] = 1296 | NonExpandedLiteralEscapeCharacterSequence(literalBegin) | 1297 | NonEscapedNonExpandedLiteralCharacterSequence(literalBegin) 1298 | 1299 | def NonExpandedLiteralEscapeCharacterSequence(literalBegin: String): Parser[String] = 1300 | regex("""\\""".r) ~ NonExpandedLiteralEscapedCharacter(literalBegin) ^^ { case r~n => "\\"+n } 1301 | 1302 | def NonExpandedLiteralEscapedCharacter(literalBegin: String): Parser[String] = 1303 | LiteralBeginningDelimiter2(literalBegin) | LiteralEndingDelimiter2(literalBegin) | regex("""\\""".r) 1304 | 1305 | def QuotedLiteralEscapeCharacter(literalBegin: String): Parser[String] = 1306 | NonExpandedLiteralEscapedCharacter(literalBegin) 1307 | 1308 | def NonEscapedNonExpandedLiteralCharacterSequence(literalBegin: String): Parser[String] = 1309 | regex("""\\""".r) ~ NonEscapedNonExpandedLiteralCharacter(literalBegin) ^^ { case r~n => "\\"+n } 1310 | 1311 | def NonEscapedNonExpandedLiteralCharacter(literalBegin: String): Parser[String] = 1312 | not(NonExpandedLiteralEscapedCharacter(literalBegin)) ~ SourceCharacter ^^ { case n~s => s } 1313 | 1314 | lazy val LiteralBeginningDelimiter: Parser[String] = 1315 | not(AlphaNumericCharacter) ~ SourceCharacter ^^ { case n~s => s } 1316 | 1317 | lazy val LiteralEndingDelimiter: Parser[String] = 1318 | not(AlphaNumericCharacter) ~ SourceCharacter ^^ { case n~s => s } 1319 | 1320 | def LiteralBeginningDelimiter2(beginString: String): Parser[String] = 1321 | LiteralBeginningDelimiter ^? { case b if beginString == b => b } 1322 | 1323 | def LiteralEndingDelimiter2(beginString: String): Parser[String] = 1324 | LiteralEndingDelimiter ^? { 1325 | case "}" if beginString == "{" => "}" 1326 | case ")" if beginString == "(" => ")" 1327 | case "]" if beginString == "[" => "]" 1328 | case ">" if beginString == "<" => ">" 1329 | case e if (beginString != "{" && beginString != "(" && beginString != "[" && beginString != "<") && 1330 | beginString == e => e } 1331 | 1332 | // 8.7.6.3.5 Quoted expanded literal strings 1333 | 1334 | lazy val QuotedExpandedLiteralString: Parser[String] = 1335 | regex("""%Q?""".r) ~ ExpandedDelimitedString ^^ { case r~n => r+n } 1336 | 1337 | lazy val ExpandedDelimitedString: Parser[String] = 1338 | LiteralBeginningDelimiter >> { case literalBegin => ((ExpandedLiteralString(literalBegin)*) ^^ { 1339 | (_).mkString } ) ~ LiteralEndingDelimiter2(literalBegin) ^^ { case s~e => literalBegin+s+e } } 1340 | 1341 | def ExpandedLiteralString(literalBegin: String): Parser[String] = 1342 | (if (literalBegin == "{" || literalBegin == "(" || literalBegin == "[" || literalBegin == "<" ) 1343 | ExpandedDelimitedString2(literalBegin) else failure("not matched") ) | 1344 | ExpandedLiteralCharacter(literalBegin) 1345 | 1346 | def ExpandedDelimitedString2(literalBegin: String): Parser[String] = 1347 | LiteralBeginningDelimiter2(literalBegin) ~ ((ExpandedLiteralString(literalBegin)*) ^^ { (_).mkString } ) ~ 1348 | LiteralEndingDelimiter2(literalBegin) ^^ { case b~s~e => b+s+e } 1349 | 1350 | def ExpandedLiteralCharacter(literalBegin: String): Parser[String] = 1351 | not(regex("""#""".r)) ~ NonEscapedLiteralCharacter(literalBegin) ^^ { case n~c => c } | 1352 | not(regex("""\$|@|\{""".r)) ~ regex("""#""".r) ^^ { case n~r => r } | 1353 | DoubleEscapeSequence | 1354 | InterpolatedCharacterSequence 1355 | 1356 | // 8.7.6.3.6 Here documents 1357 | 1358 | def rebuild(a: Reader[Char], newSource: String, newOffset: Int): Reader[Char] = new Reader[Char] { 1359 | def atEnd = a.atEnd 1360 | def first = a.first 1361 | def pos = a.pos 1362 | def rest = rebuild(a.rest, newSource, offset + 1) 1363 | override def source = newSource 1364 | override def offset = newOffset 1365 | } 1366 | def concat(a: Reader[Char], b: Reader[Char]): Reader[Char] = new PackratReader({ 1367 | val aSource = a.source + b.source.subSequence(b.offset, b.source.length()).toString 1368 | if(a.atEnd) { 1369 | rebuild(b, aSource, a.offset) 1370 | } else { 1371 | new Reader[Char] { 1372 | private lazy val result = concat(a.rest, b) 1373 | def atEnd = a.atEnd 1374 | def first = a.first 1375 | def pos = a.pos 1376 | def rest = result 1377 | override def source = aSource 1378 | override def offset = a.offset 1379 | } 1380 | } 1381 | }) 1382 | 1383 | lazy val HereDocument: Parser[String] = 1384 | HeredocStartLine >> { case (sig, rest) => 1385 | HeredocBody(sig) ~ HeredocEndLine(sig) >> { case b ~ e => 1386 | val line = new CharSequenceReader(rest, 0) 1387 | Parser{next => Success("Heredoc(\"" + b + "\")", concat(line, next))} 1388 | } 1389 | } 1390 | 1391 | // lazy val HereDocument: Parser[String] = 1392 | // HeredocStartLine >> { case heredocDelimiter => HeredocBody(heredocDelimiter) ~ 1393 | // HeredocEndLine(heredocDelimiter) ^^ { case b~e => "Heredoc(\n"+b+")" } } 1394 | lazy val HeredocStartLine: Parser[(String, String)] = 1395 | HeredocSignifier ~ RestOfLine ^^ { case s~r => (s, r) } 1396 | 1397 | // lazy val HeredocStartLine: Parser[String] = 1398 | // HeredocSignifier ~ RestOfLine ^^ { case s~r => s } 1399 | lazy val HeredocSignifier: Parser[String] = 1400 | regex("""<<""".r) ~ HeredocDelimiterSpecifier ^^ { case r~s => s } 1401 | 1402 | lazy val RestOfLine: Parser[String] = 1403 | LineContent ~ LineTerminator ^^ { case c~t => c+"\n" } 1404 | 1405 | def HeredocBody(heredocDelimiter: String): Parser[String] = 1406 | (HeredocBodyLine(heredocDelimiter)*) ^^ { (_).mkString } 1407 | 1408 | def HeredocBodyLine(heredocDelimiter: String): Parser[String] = 1409 | not(HeredocEndLine(heredocDelimiter)) ~ LineContent ~ LineTerminator ^^ { case n~c~t => c+"\n" } 1410 | 1411 | lazy val HeredocDelimiterSpecifier: Parser[String] = 1412 | regex("""\-?""".r) ~ HeredocDelimiter ^^ { case r~d => r+d } 1413 | 1414 | lazy val HeredocDelimiter: Parser[String] = 1415 | NonQuotedDelimiter | 1416 | SingleQuotedDelimiter | 1417 | DoubleQuotedDelimiter | 1418 | CommandQuotedDelimiter 1419 | 1420 | lazy val NonQuotedDelimiter: Parser[String] = 1421 | NonQuotedDelimiterIdentifier 1422 | 1423 | lazy val NonQuotedDelimiterIdentifier: Parser[String] = 1424 | (IdentifierCharacter*) ^^ { (_).mkString } 1425 | 1426 | lazy val SingleQuotedDelimiter: Parser[String] = 1427 | regex("""'""".r) ~ SingleQuotedDelimiterIdentifier ~ regex("""'""".r) ^^ { 1428 | case r1~i~r2 => "'"+i+"'" } 1429 | 1430 | lazy val SingleQuotedDelimiterIdentifier: Parser[String] = 1431 | ( (not(regex("""'""".r) | LineTerminator) ~ SourceCharacter)*) ^^ { (_).mkString } 1432 | 1433 | lazy val DoubleQuotedDelimiter: Parser[String] = 1434 | regex(""""""".r) ~ DoubleQuotedDelimiterIdentifier ~ regex(""""""".r) ^^ { 1435 | case r1~i~r2 => "\""+i+"\"" } 1436 | 1437 | lazy val DoubleQuotedDelimiterIdentifier: Parser[String] = 1438 | ( (not(regex(""""""".r) | LineTerminator) ~ SourceCharacter)*) ^^ { (_).mkString } 1439 | 1440 | lazy val CommandQuotedDelimiter: Parser[String] = 1441 | regex("""`""".r) ~ CommandQuotedDelimiterIdentifier ~ regex("""`""".r) ^^ { 1442 | case r1~i~r2 => "`"+i+"`" } 1443 | 1444 | lazy val CommandQuotedDelimiterIdentifier: Parser[String] = 1445 | ( (not(regex("""`""".r) | LineTerminator) ~ SourceCharacter)*) ^^ { (_).mkString } 1446 | 1447 | def HeredocEndLine(heredocDelimiter: String): Parser[String] = 1448 | if (heredocDelimiter.head == '-') IndentedHeredocEndLine(heredocDelimiter) else 1449 | NonIndentedHeredocEndLine(heredocDelimiter) 1450 | 1451 | def IndentedHeredocEndLine(heredocDelimiter: String): Parser[String] = 1452 | regex("""^""".r) ~ ((Whitespace*) ^^ { (_).mkString }) ~ ( HeredocDelimiterIdentifier ^? { 1453 | case a if a == heredocDelimiter => a }) ~ LineTerminator ^^ { case r~w~i~t => w+i+"\n" } 1454 | 1455 | def NonIndentedHeredocEndLine(heredocDelimiter: String): Parser[String] = 1456 | regex("""^""".r) ~ ( HeredocDelimiterIdentifier ^? { case a if a == heredocDelimiter => a }) ~ 1457 | LineTerminator ^^ { case r~i~t => i+"\n" } 1458 | 1459 | lazy val HeredocDelimiterIdentifier: Parser[String] = 1460 | NonQuotedDelimiterIdentifier | 1461 | SingleQuotedDelimiterIdentifier | 1462 | DoubleQuotedDelimiterIdentifier | 1463 | CommandQuotedDelimiterIdentifier 1464 | 1465 | // 8.7.6.3.7 External command execution 1466 | 1467 | lazy val ExternalCommandExecution: Parser[String] = 1468 | BackquotedExternalCommandExecution | 1469 | QuotedExternalCommandExecution 1470 | 1471 | lazy val BackquotedExternalCommandExecution: Parser[String] = 1472 | regex("""`""".r) ~ ((BackquotedExternalCommandExecutionCharacter*) ^^ { (_).mkString } ) ~ 1473 | regex("""`""".r) ^^ { case r1~s~r2 => "`"+s+"`" } 1474 | 1475 | lazy val BackquotedExternalCommandExecutionCharacter: Parser[String] = 1476 | not(regex("""`|#|\\""".r)) ~ SourceCharacter ^^ { case n~c => c } | 1477 | not(regex("""\$|@|\{""".r)) ~ regex("""#""".r) ^^ { case n~r => r } | 1478 | DoubleEscapeSequence | 1479 | InterpolatedCharacterSequence 1480 | 1481 | lazy val QuotedExternalCommandExecution: Parser[String] = 1482 | regex("""%x""".r) ~ ExpandedDelimitedString ^^ { case r~n => r+n } 1483 | 1484 | // 8.7.6.4 Array literals 1485 | 1486 | lazy val ArrayLiteral: Parser[String] = QuotedNonExpandedArrayConstructor | QuotedExpandedArrayConstructor 1487 | 1488 | lazy val QuotedArrayItemSeparatorList: Parser[String] = (QuotedArrayItemSeparator+) ^^ {_.mkString } 1489 | 1490 | lazy val QuotedArrayItemSeparator: Parser[String] = Whitespace | LineTerminator 1491 | 1492 | lazy val QuotedNonExpandedArrayConstructor: Parser[String] = regex("""%w""".r) ~ ( 1493 | LiteralBeginningDelimiter >> { case literalBegin => 1494 | (NonExpandedArrayContent(literalBegin) >> { case content => 1495 | Parser{next => Success(content.split(" ").mkString("__"), next)} 1496 | }) ~ LiteralEndingDelimiter2(literalBegin) ^^ { case a~e => "'" + literalBegin + "'" + a+ "'" + e + "'" } 1497 | } 1498 | ) ^^ { case r~s => s"|${r}|" + s } 1499 | 1500 | def NonExpandedArrayContent(literalBegin: String): Parser[String] = (??(QuotedArrayItemSeparatorList) ~> NonExpandedArrayItemList(literalBegin).+ <~ ??(QuotedArrayItemSeparatorList) ) ^^ {_.flatten.mkString} 1501 | 1502 | def NonExpandedArrayItemList(literalBegin: String): Parser[String] = rep1sep( 1503 | NonExpandedArrayItem(literalBegin) | (LiteralBeginningDelimiter2(literalBegin) ~ NonExpandedArrayItemList(literalBegin) ~ LiteralEndingDelimiter2(literalBegin)) ^^ { case a1 ~ a2 ~ a3 => a1 + a2 + a3 }, 1504 | QuotedArrayItemSeparatorList 1505 | ) ^^ {_.mkString(" ")} 1506 | 1507 | def NonExpandedArrayItem(literalBegin: String): Parser[String] = NonExpandedArrayItemCharacter(literalBegin).+ ^^ {_.mkString} 1508 | 1509 | def NonExpandedArrayItemCharacter(literalBegin: String): Parser[String] = NonEscapedArrayCharacter(literalBegin) | NonExpandedArrayEscapeSequence(literalBegin) 1510 | 1511 | def NonEscapedArrayCharacter(literalBegin: String): Parser[String] = not(QuotedArrayItemSeparator) ~ NonExpandedLiteralCharacter(literalBegin)^^ { case n~s => s } 1512 | 1513 | def NonExpandedArrayEscapeSequence(literalBegin: String): Parser[String] = NonExpandedLiteralEscapeSequence(literalBegin) | regex("""\\""".r) ~ QuotedArrayItemSeparator ^^ { case r~s => r+s } 1514 | 1515 | lazy val QuotedExpandedArrayConstructor: Parser[String] = regex("""%W""".r) ~ ( 1516 | LiteralBeginningDelimiter >> { case literalBegin => 1517 | (ExpandedArrayContent(literalBegin) >> { case content => 1518 | Parser{next => Success(content.split(" ").mkString("__"), next)} 1519 | }) ~ LiteralEndingDelimiter2(literalBegin) ^^ { case a~e => "'" + literalBegin + "'" + a+ "'" + e + "'" } 1520 | } 1521 | ) ^^ { case r~s => r+s } 1522 | 1523 | def ExpandedArrayContent(literalBegin: String): Parser[String] = ??(QuotedArrayItemSeparatorList) ~> ExpandedArrayItemList(literalBegin).+ <~ ??(QuotedArrayItemSeparatorList) ^^ {_.flatten.mkString} 1524 | 1525 | def ExpandedArrayItemList(literalBegin: String): Parser[String] = rep1sep( 1526 | ExpandedArrayItem(literalBegin) | (LiteralBeginningDelimiter2(literalBegin) ~ ExpandedArrayItemList(literalBegin) ~ LiteralEndingDelimiter2(literalBegin)) ^^ { case a1 ~ a2 ~ a3 => a1 + a2 + a3 }, 1527 | QuotedArrayItemSeparatorList 1528 | ) ^^ {_.mkString(" ")} 1529 | 1530 | def ExpandedArrayItem(literalBegin: String): Parser[String] = ExpandedArrayItemCharacter(literalBegin).+ ^^ {_.mkString} 1531 | 1532 | def ExpandedArrayItemCharacter(literalBegin: String): Parser[String] = 1533 | NonEscapedArrayItemCharacter(literalBegin) | not(regex("""\$|@|\{""".r)) ~ regex("""#""".r) ^^ { case n~r => r } | ExpandedArrayEscapeSequence | InterpolatedCharacterSequence 1534 | 1535 | def NonEscapedArrayItemCharacter(literalBegin: String): Parser[String] = 1536 | not(QuotedArrayItemSeparator | regex("""\\|#""".r)) ~> NonExpandedLiteralCharacter(literalBegin)^? { 1537 | case s if literalBegin =="(" || literalBegin =="{" || literalBegin =="[" || literalBegin =="<" || literalBegin != s => s 1538 | } 1539 | lazy val ExpandedArrayEscapeSequence: Parser[String] = DoubleEscapeSequence | regex("""\\""".r) ~ QuotedArrayItemSeparator ^^ { case r~s => r+s } 1540 | 1541 | // 8.7.6.5 Regular expression literals 1542 | 1543 | lazy val RegularExpressionLiteral: Parser[String] = 1544 | regex("""/""".r) ~ RegularExpressionBody ~ regex("""/""".r) ~ ((RegularExpressionOption*) ^^ { 1545 | (_).mkString }) ^^ { case r1~b~r2~o => "/"+b+"/"+o } | 1546 | regex("""%r""".r) ~ LiteralBeginningDelimiter >> { case r~literalBegin => 1547 | ( (ExpandedLiteralString(literalBegin)*) ^^ { (_).mkString } ) ~ 1548 | LiteralEndingDelimiter2(literalBegin) ~ ((RegularExpressionOption*) ^^ { (_).mkString }) ^^ { 1549 | case s~e~o => "%r"+literalBegin+s+e } } 1550 | lazy val RegularExpressionBody: Parser[String] = 1551 | (RegularExpressionCharacter*) ^^ { (_).mkString } 1552 | lazy val RegularExpressionCharacter: Parser[String] = 1553 | not(regex("""/|#|\\""".r)) ~ SourceCharacter ^^ { case n~c => c } | 1554 | not(regex("""\$|@|\{""".r)) ~ regex("""#""".r) ^^ { case n~r => r } | 1555 | RegularExpressionNonEscapedSequence | 1556 | RegularExpressionEscapeSequence | 1557 | LineTerminatorEscapeSequence | 1558 | InterpolatedCharacterSequence 1559 | lazy val RegularExpressionNonEscapedSequence: Parser[String] = 1560 | regex("""\\""".r) ~ RegularExpressionNonEscapedCharacter ^^ { case r~c => "\\"+c } 1561 | lazy val RegularExpressionNonEscapedCharacter: Parser[String] = 1562 | not(regex("""\u000d|\u000a""".r)) ~ SourceCharacter ^^ { case n~c => c } | 1563 | regex("""\u000d""".r) ~ not(regex("""\u000a""".r)) ^^ { case d~a => d } 1564 | lazy val RegularExpressionEscapeSequence: Parser[String] = 1565 | regex("""\\/""".r) 1566 | lazy val RegularExpressionOption: Parser[String] = 1567 | regex("""i|m""".r) 1568 | 1569 | // 8.7.6.6 Symbol literals 1570 | lazy val Symbol: Parser[String] = 1571 | SymbolLiteral | 1572 | DynamicSymbol 1573 | lazy val SymbolLiteral: Parser[String] = 1574 | regex(""":""".r) ~ SymbolName ^^ { case r~s => ":"+s } 1575 | lazy val DynamicSymbol: Parser[String] = 1576 | regex(""":""".r) ~ SingleQuotedString ^^ { case r~s => ":"+s } | 1577 | regex(""":""".r) ~ DoubleQuotedString ^^ { case r~s => ":"+s } | 1578 | regex("""%s""".r) ~ LiteralBeginningDelimiter >> { case r~literalBegin => 1579 | ( (NonExpandedLiteralString(literalBegin)*) ^^ { (_).mkString } ) ~ 1580 | LiteralEndingDelimiter2(literalBegin) ^^ { case s~e => "%s"+literalBegin+s+e } } 1581 | lazy val SymbolName: Parser[String] = 1582 | InstanceVariableIdentifier | 1583 | GlobalVariableIdentifier | 1584 | ClassVariableIdentifier | 1585 | ConstantIdentifier | 1586 | LocalVariableIdentifier | 1587 | MethodOnlyIdentifier | 1588 | AssignmentLikeMethodIdentifier | 1589 | OperatorMethodName | 1590 | Keyword 1591 | 1592 | 1593 | } 1594 | -------------------------------------------------------------------------------- /src/main/scala/com/github/inakata/ruby_scala/RubyParser.scala: -------------------------------------------------------------------------------- 1 | package com.github.inakata.ruby_scala 2 | 3 | import java.io.FileReader 4 | object RubyParser extends Ruby { 5 | def main(args: Array[String]) { 6 | val reader = new FileReader(args(0)) 7 | println(parseAll(program, reader)) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/com/github/inakata/ruby_scala/TracableParsers.scala: -------------------------------------------------------------------------------- 1 | package com.github.inakata.ruby_scala 2 | 3 | import scala.util.parsing.combinator._ 4 | import scala.util.parsing.input._ 5 | 6 | trait TracableParsers extends Parsers {self => 7 | private lazy val names: Map[Parser[Any], String] = { 8 | val rules = this.getClass().getMethods().filter{m => m.getParameterTypes().length == 0 && (m.getReturnType() eq classOf[Parser[_]])} 9 | rules.foldLeft(Map[Parser[_], String]()){(m, r) => m.updated(r.invoke(self).asInstanceOf[Parser[_]], r.getName())} 10 | } 11 | class Parser[+T](wrapped: super.Parser[T]) extends super.Parser[T] { 12 | def apply(in: Input): ParseResult[T] = { 13 | val name = names.get(this).getOrElse("?") 14 | val flag = false // name.head.isLower && name != "anySpace" 15 | if (flag) println("app " + name + ":" + in.pos) 16 | val result = wrapped(in) 17 | if (flag) { 18 | print("ret " + name +" "+ result.toString+";") 19 | result match { 20 | case Failure(_, next) => println(" Failed: " + next.pos) 21 | case Success(_, next) => println(" Succeeded: " + next.pos) 22 | } 23 | } 24 | result 25 | } 26 | } 27 | implicit def toTracable[T](wrapped: super.Parser[T]): Parser[T] = { 28 | new Parser[T](wrapped) 29 | } 30 | } 31 | --------------------------------------------------------------------------------