diff --git a/spec/tags/truffle/parsing/parsing_tags.txt b/spec/tags/truffle/parsing/parsing_tags.txt index 44e7e6e4557b..a9b4cac8ee04 100644 --- a/spec/tags/truffle/parsing/parsing_tags.txt +++ b/spec/tags/truffle/parsing/parsing_tags.txt @@ -1,3 +1,4 @@ -fails:Parsing a BEGIN block (BEGIN { ... }) case is parsed correctly -fails:Parsing a END block (END { ... }) case is parsed correctly -fails:Parsing a For operator (for ... in ... operator) case is parsed correctly +# Not supported yet by Prism +# See https://github.com/ruby/prism/issues/1997 +fails:Parsing a Regexp (encoding / when there are non-ASCII characters in a literal) case is parsed correctly +fails:Parsing a Regexp (encoding in boolean context / when there are non-ASCII characters in a literal) case is parsed correctly diff --git a/spec/truffle/parsing/fixtures/BEGIN.yaml b/spec/truffle/parsing/fixtures/BEGIN.yaml deleted file mode 100644 index 5de6c62f0d9e..000000000000 --- a/spec/truffle/parsing/fixtures/BEGIN.yaml +++ /dev/null @@ -1,44 +0,0 @@ -subject: "BEGIN block" -description: "BEGIN { ... }" -focused_on_node: "org.truffleruby.language.control.SequenceNode" -ruby: | - BEGIN { - 1 - 2 - } -ast: | - SequenceNode - attributes: - flags = 12 - children: - body = [ - EmitWarningsNode - attributes: - flags = 0 - warnings = RubyDeferredWarnings(WarningMessage(message = 'Useless use of a literal in void context.', verbosity = VERBOSE, fileName = '', lineNumber = 2)) - WriteLocalVariableNode - attributes: - flags = 0 - frameSlot = 0 # (self) - children: - valueNode = - ProfileArgumentNodeGen - attributes: - flags = 0 - children: - childNode_ = - ReadSelfNode - attributes: - flags = 0 - IntegerFixnumLiteralNode - attributes: - flags = 1 - value = 1 - IntegerFixnumLiteralNode - attributes: - flags = 1 - value = 2 - NilLiteralNode - attributes: - flags = 0 - ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/BEGIN/BEGIN.yaml b/spec/truffle/parsing/fixtures/BEGIN/BEGIN.yaml new file mode 100644 index 000000000000..2613f4f64b2e --- /dev/null +++ b/spec/truffle/parsing/fixtures/BEGIN/BEGIN.yaml @@ -0,0 +1,95 @@ +subject: "BEGIN block" +description: "BEGIN { ... }" +notes: > + Put content of the BEGIN block at the beginning of the program. + So actual sequence of expressions is: + + ```ruby + a + b + ``` +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" +ruby: | + b + BEGIN { + a + } +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "b" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/BEGIN/when_multiple_occurrences.yaml b/spec/truffle/parsing/fixtures/BEGIN/when_multiple_occurrences.yaml new file mode 100644 index 000000000000..9e02d103d726 --- /dev/null +++ b/spec/truffle/parsing/fixtures/BEGIN/when_multiple_occurrences.yaml @@ -0,0 +1,125 @@ +subject: "BEGIN block" +description: "when multiple occurrences in a program" +notes: > + Put content of the BEGIN blocks in order they are located in a program. + So sequence of expressions is: + + ```ruby + a + b + c + ``` +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" +ruby: | + BEGIN { + a + } + + BEGIN { + b + } + + BEGIN { + c + } +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "b" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "c" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + NilLiteralNode + attributes: + flags = 0 + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/END.yaml b/spec/truffle/parsing/fixtures/END.yaml index 28f7cf811614..e46889e84001 100644 --- a/spec/truffle/parsing/fixtures/END.yaml +++ b/spec/truffle/parsing/fixtures/END.yaml @@ -1,7 +1,9 @@ subject: "END block" description: "END { ... }" notes: > - Is trasnalted into a `Truffle::KernelOperations.at_exit(false) { ... }` call. + Is translated into a `Truffle::KernelOperations.at_exit(false) { ... }` call. +yarp_specific: true # don't optimize reading KernelOperations constant + # with TruffleKernelOperationsModuleLiteralNode focused_on_node: "org.truffleruby.language.control.OnceNode" ruby: | END { @@ -11,7 +13,7 @@ ruby: | ast: | OnceNode attributes: - flags = 0 + flags = 1 holder = org.truffleruby.language.control.OnceNode$Holder@... children: child = @@ -56,7 +58,7 @@ ast: | callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) flags = 0 frameOnStackMarkerSlot = 2 - sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = []) + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = []) type = PROC call targets: RubyProcRootNode @@ -70,7 +72,7 @@ ast: | redoProfile = false retryProfile = false returnID = org.truffleruby.language.control.ReturnID@... - sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = []) + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = []) split = HEURISTIC children: body = @@ -103,6 +105,16 @@ ast: | value = 2 ] receiver = - TruffleKernelOperationsModuleLiteralNode + ReadConstantWithLexicalScopeNode attributes: - flags = 0 \ No newline at end of file + flags = 0 + lexicalScope = :: Object + name = "KernelOperations" + children: + getConstantNode = + GetConstantNodeGen + lookupConstantNode = + LookupConstantWithLexicalScopeNodeGen + attributes: + lexicalScope = :: Object + name = "KernelOperations" \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_multiple_variables.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_multiple_variables.yaml new file mode 100644 index 000000000000..b41b686d5e0e --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_multiple_variables.yaml @@ -0,0 +1,220 @@ +subject: "For operator" +description: "multi-assignment / with multiple variables (for a, b, c in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a, b, c in [42, 100500] + array = [a, b, c] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b, #5:c, #6:array} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + ] + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 6 # array + children: + valueNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + type = FRAME_LOCAL + ] + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_nested_multi_assignment.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_nested_multi_assignment.yaml new file mode 100644 index 000000000000..fe9159bc2a4a --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_nested_multi_assignment.yaml @@ -0,0 +1,233 @@ +subject: "For operator" +description: "multi-assignment / with nested multi assignment (for a, (b, c) in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a, (b, c) in [42, 100500] + array = [a, b, c] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b, #5:c, #6:array} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + MultipleAssignmentNode + attributes: + flags = 0 + children: + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + ] + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + ] + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 6 # array + children: + valueNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + type = FRAME_LOCAL + ] + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_splat_operator_and_following_variables.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_splat_operator_and_following_variables.yaml new file mode 100644 index 000000000000..d397559ef599 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_splat_operator_and_following_variables.yaml @@ -0,0 +1,223 @@ +subject: "For operator" +description: "multi-assignment / with preceding variables, splat operator and following variables (for a, *b, c in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a, *b, c in [42, 100500] + array = [a, b, c] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b, #5:c, #6:array} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + postNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + ] + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + ] + restNode = + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 6 # array + children: + valueNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + type = FRAME_LOCAL + ] + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_implicit_rest.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_implicit_rest.yaml new file mode 100644 index 000000000000..49191527e0c6 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_implicit_rest.yaml @@ -0,0 +1,191 @@ +subject: "For operator" +description: "multi-assignment / with preceding variables and implicit rest (for a, in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a, in [42, 100500] + b = a + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + ] + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 4 # b + children: + valueNode = + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_splat_operator.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_splat_operator.yaml new file mode 100644 index 000000000000..78a83fb2cd28 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_preceding_variables_and_splat_operator.yaml @@ -0,0 +1,221 @@ +subject: "For operator" +description: "multi-assignment / with preceding variables and splat operator (for a, b, *c in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a, b, *c in [42, 100500] + array = [a, b, c] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b, #5:c, #6:array} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + preNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + ] + restNode = + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 6 # array + children: + valueNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + type = FRAME_LOCAL + ] + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/multi_assignment/with_splat_operator_and_following_variables.yaml b/spec/truffle/parsing/fixtures/for/multi_assignment/with_splat_operator_and_following_variables.yaml new file mode 100644 index 000000000000..54b730e545e5 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/multi_assignment/with_splat_operator_and_following_variables.yaml @@ -0,0 +1,221 @@ +subject: "For operator" +description: "multi-assignment / with splat operator and following variables (for *a, b, c in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for *a, b, c in [42, 100500] + array = [a, b, c] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b, #5:c, #6:array} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + MultipleAssignmentNode + attributes: + flags = 0 + children: + postNodes = [ + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + ] + restNode = + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + rhsNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 6 # array + children: + valueNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 4 # b + type = FRAME_LOCAL + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 5 # c + type = FRAME_LOCAL + ] + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_attribute_assignment.yaml b/spec/truffle/parsing/fixtures/for/with_attribute_assignment.yaml new file mode 100644 index 000000000000..47997e7a7651 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_attribute_assignment.yaml @@ -0,0 +1,238 @@ +subject: "For operator" +description: "with attribute assignment (for a.b in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a.foo in [42, 100500] + b = a.foo + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = true + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "foo=" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + ] + receiver = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "foo" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_class_variable.yaml b/spec/truffle/parsing/fixtures/for/with_class_variable.yaml new file mode 100644 index 000000000000..8fb8fb2ae388 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_class_variable.yaml @@ -0,0 +1,195 @@ +subject: "For operator" +description: "with class variable (for @@a in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for @@a in [42, 100500] + b = @@a + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteClassVariableNode + attributes: + flags = 0 + name = "@@a" + children: + lexicalScopeNode = + ObjectLiteralNode + attributes: + flags = 0 + object = :: Object + resolveTargetModuleNode = + ResolveTargetModuleForClassVariablesNodeGen + rhs = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + setClassVariableNode = + SetClassVariableNodeGen + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + ReadClassVariableNode + attributes: + flags = 0 + name = "@@a" + children: + lexicalScopeNode = + ObjectLiteralNode + attributes: + flags = 0 + object = :: Object + lookupClassVariableNode = + LookupClassVariableNodeGen + resolveTargetModuleNode = + ResolveTargetModuleForClassVariablesNodeGen + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_constant.yaml b/spec/truffle/parsing/fixtures/for/with_constant.yaml new file mode 100644 index 000000000000..84cbefd4a23d --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_constant.yaml @@ -0,0 +1,190 @@ +subject: "For operator" +description: "with constant (for A in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for A in [42, 100500] + b = A + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteConstantNode + attributes: + flags = 0 + name = "A" + children: + moduleNode = + LexicalScopeNode + attributes: + flags = 0 + lexicalScope = :: Object + valueNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + ReadConstantWithLexicalScopeNode + attributes: + flags = 0 + lexicalScope = :: Object + name = "A" + children: + getConstantNode = + GetConstantNodeGen + lookupConstantNode = + LookupConstantWithLexicalScopeNodeGen + attributes: + lexicalScope = :: Object + name = "A" + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_fully_qualified_constant.yaml b/spec/truffle/parsing/fixtures/for/with_fully_qualified_constant.yaml new file mode 100644 index 000000000000..ece273a1cce1 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_fully_qualified_constant.yaml @@ -0,0 +1,205 @@ +subject: "For operator" +description: "with fully qualified constant (for A in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for A::B in [42, 100500] + b = A::B + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteConstantNode + attributes: + flags = 0 + name = "B" + children: + moduleNode = + ReadConstantWithLexicalScopeNode + attributes: + flags = 0 + lexicalScope = :: Object + name = "A" + children: + getConstantNode = + GetConstantNodeGen + lookupConstantNode = + LookupConstantWithLexicalScopeNodeGen + attributes: + lexicalScope = :: Object + name = "A" + valueNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + ReadConstantNode + attributes: + flags = 0 + name = "B" + children: + moduleNode = + ReadConstantWithLexicalScopeNode + attributes: + flags = 0 + lexicalScope = :: Object + name = "A" + children: + getConstantNode = + GetConstantNodeGen + lookupConstantNode = + LookupConstantWithLexicalScopeNodeGen + attributes: + lexicalScope = :: Object + name = "A" + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_global_variable.yaml b/spec/truffle/parsing/fixtures/for/with_global_variable.yaml new file mode 100644 index 000000000000..22d376e46b00 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_global_variable.yaml @@ -0,0 +1,187 @@ +subject: "For operator" +description: "with global variable (for $a in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for $a in [42, 100500] + b = $a + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteGlobalVariableNodeGen + attributes: + flags = 0 + name = "$a" + children: + lookupGlobalVariableStorageNode = + LookupGlobalVariableStorageNodeGen + attributes: + index = -1 + name = "$a" + valueNode_ = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + ReadGlobalVariableNodeGen + attributes: + flags = 0 + name = "$a" + children: + lookupGlobalVariableStorageNode = + LookupGlobalVariableStorageNodeGen + attributes: + index = -1 + name = "$a" + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_instance_variable.yaml b/spec/truffle/parsing/fixtures/for/with_instance_variable.yaml new file mode 100644 index 000000000000..d326df592f48 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_instance_variable.yaml @@ -0,0 +1,186 @@ +subject: "For operator" +description: "with instance variable (for @a in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for @a in [42, 100500] + b = @a + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteInstanceVariableNodeGen + attributes: + flags = 0 + frozenProfile = false + name = "@a" + children: + readSelfSlotNode = + ReadFrameSlotNodeGen + attributes: + frameSlot = 0 # (self) + rhs = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + ReadInstanceVariableNode + attributes: + flags = 0 + name = "@a" + children: + readSelfSlotNode = + ReadFrameSlotNodeGen + attributes: + frameSlot = 0 # (self) + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_local_variable.yaml b/spec/truffle/parsing/fixtures/for/with_local_variable.yaml new file mode 100644 index 000000000000..d1b5214bb4e8 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_local_variable.yaml @@ -0,0 +1,179 @@ +subject: "For operator" +description: "with local variable (for a in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a in [42, 100500] + b = a + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:a, #4:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + WriteDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + children: + valueNode = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 4 # b + children: + valueNode = + ReadDeclarationVariableNode + attributes: + flags = 0 + frameDepth = 1 + frameSlot = 3 # a + type = FRAME_LOCAL + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_reference_assignment.yaml b/spec/truffle/parsing/fixtures/for/with_reference_assignment.yaml new file mode 100644 index 000000000000..95f2bfb60fd8 --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_reference_assignment.yaml @@ -0,0 +1,229 @@ +subject: "For operator" +description: "with reference assignment (for a[b] in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a[:foo] in [42, 100500] + b = a[:foo] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + InlinedIndexSetNodeGen + attributes: + assumptions = [Assumption(valid, name=set_trace_func is not used)] + flags = 0 + parameters = RubyCallNodeParameters{methodName='[]=', descriptor=NoKeywordArgumentsDescriptor, isSplatted=false, ignoreVisibility=false, isVCall=false, isSafeNavigation=false, isAttrAssign=true} + children: + operand1Node_ = + ObjectLiteralNode + attributes: + flags = 0 + object = :foo + operand2Node_ = + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + receiver_ = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + InlinedIndexGetNodeGen + attributes: + assumptions = [Assumption(valid, name=set_trace_func is not used)] + flags = 0 + parameters = RubyCallNodeParameters{methodName='[]', descriptor=NoKeywordArgumentsDescriptor, isSplatted=false, ignoreVisibility=false, isVCall=false, isSafeNavigation=false, isAttrAssign=false} + children: + leftNode_ = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + rightNode_ = + ObjectLiteralNode + attributes: + flags = 0 + object = :foo + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for/with_reference_assignment_and_multiple_explicit_arguments.yaml b/spec/truffle/parsing/fixtures/for/with_reference_assignment_and_multiple_explicit_arguments.yaml new file mode 100644 index 000000000000..f1a8cdecbe8a --- /dev/null +++ b/spec/truffle/parsing/fixtures/for/with_reference_assignment_and_multiple_explicit_arguments.yaml @@ -0,0 +1,256 @@ +subject: "For operator" +description: "with reference assignment and multiple explicit arguments (for a[b, c] in [])" +focused_on_node: "org.truffleruby.language.RubyTopLevelRootNode" # to dump local variable declarations in outer scope +ruby: | + for a[:foo, :bar] in [42, 100500] + b = a[:foo, :bar] + end +ast: | + RubyTopLevelRootNode + attributes: + arityForCheck = Arity{preRequired = 0, optional = 0, hasRest = true, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false} + callTarget = + checkArityProfile = false + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%$~_, #2:%frame_on_stack_marker_1, #3:b} + instrumentationBits = 0 + keywordArguments = false + localReturnProfile = false + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + matchingReturnProfile = false + nextProfile = false + nonMatchingReturnProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 0, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = , blockDepth = 0, parseName = , notes = null, argumentDescriptors = null) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + CatchBreakNode + attributes: + breakID = org.truffleruby.language.control.BreakID@... + flags = 0 + isWhile = false + children: + body = + FrameOnStackNode + attributes: + flags = 0 + frameOnStackMarkerSlot = 2 + children: + child = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "each" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + block = + BlockDefinitionNodeGen + attributes: + breakID = org.truffleruby.language.control.BreakID@... + callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) + flags = 0 + frameOnStackMarkerSlot = 2 + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + type = PROC + call targets: + RubyProcRootNode + attributes: + callTarget = block in + frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} + instrumentationBits = 0 + lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] + nextProfile = false + polyglotRef = org.truffleruby.RubyLanguage@... + redoProfile = false + retryProfile = false + returnID = org.truffleruby.language.control.ReturnID@... + sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, isImplicitRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) + split = HEURISTIC + children: + body = + SequenceNode + attributes: + flags = 12 + children: + body = [ + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 0 # (self) + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadSelfNode + attributes: + flags = 0 + WriteLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + children: + valueNode = + ProfileArgumentNodeGen + attributes: + flags = 0 + children: + childNode_ = + ReadPreArgumentNode + attributes: + flags = 0 + index = 0 + keywordArguments = false + missingArgumentBehavior = NIL + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = true + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "[]=" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ObjectLiteralNode + attributes: + flags = 0 + object = :foo + ObjectLiteralNode + attributes: + flags = 0 + object = :bar + ReadLocalVariableNode + attributes: + flags = 0 + frameSlot = 1 # %for_0 + type = FRAME_LOCAL + ] + receiver = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + WriteDeclarationVariableNode + attributes: + flags = 1 + frameDepth = 1 + frameSlot = 3 # b + children: + valueNode = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "[]" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ObjectLiteralNode + attributes: + flags = 0 + object = :foo + ObjectLiteralNode + attributes: + flags = 0 + object = :bar + ] + receiver = + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 0 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = true + lastArgIsNotHashProfile = false + methodName = "a" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + receiver = + SelfNode + attributes: + flags = 0 + ] + receiver = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + children: + values = [ + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 42 + IntegerFixnumLiteralNode + attributes: + flags = 0 + value = 100500 + ] + ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/for_operator.yaml b/spec/truffle/parsing/fixtures/for_operator.yaml deleted file mode 100644 index 5148cdee28c4..000000000000 --- a/spec/truffle/parsing/fixtures/for_operator.yaml +++ /dev/null @@ -1,161 +0,0 @@ -subject: "For operator" -description: "for ... in ... operator" -notes: > - for ... in loop is represented as an #each method call, so - - ```ruby - for i in array do - # ... - end - ``` - - Is represented as: - - ```ruby - array.each do |tmp| - i = tmp - # ... - end - ``` - - A simplified AST for a block is the following: - - (WriteLocalVariableNode - 0 # frameSlot - (ReadSelfNode)) - - (WriteLocalVariableNode - 1 # frameSlot, variable `tmp` - (ReadPreArgumentNode - 0) # index - - (WriteDeclarationVariableNode - 4 # frameSlot, variable `i` - (ReadLocalVariableNode - 1)) # frameSlot - - (NilLiteralNode) - - Note that both i and any local variable in the `for`'s body are declared in the outer scope. -focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" -ruby: | - for i in [42, 100500] - inner = 1 - end -ast: | - RubyCallNode - attributes: - descriptor = NoKeywordArgumentsDescriptor - dispatchConfig = PROTECTED - emptyKeywordsProfile = false - flags = 0 - isAttrAssign = false - isSafeNavigation = false - isSplatted = false - isVCall = false - lastArgIsNotHashProfile = false - methodName = "each" - notEmptyKeywordsProfile = false - notRuby2KeywordsHashProfile = false - children: - block = - BlockDefinitionNodeGen - attributes: - breakID = org.truffleruby.language.control.BreakID@... - callTargets = ProcCallTargets(callTargetForProc = block in , callTargetForLambda = null, altCallTargetCompiler = ...$$Lambda$.../0x...@...) - flags = 0 - frameOnStackMarkerSlot = 3 - sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) - type = PROC - call targets: - RubyProcRootNode - attributes: - callTarget = block in - frameDescriptor = FrameDescriptor@...{#0:(self), #1:%for_0} - instrumentationBits = 0 - lock = java.util.concurrent.locks.ReentrantLock@...[Unlocked] - nextProfile = false - polyglotRef = org.truffleruby.RubyLanguage@... - redoProfile = false - retryProfile = false - returnID = org.truffleruby.language.control.ReturnID@... - sharedMethodInfo = SharedMethodInfo(staticLexicalScope = :: Object, arity = Arity{preRequired = 1, optional = 0, hasRest = false, postRequired = 0, keywordArguments = [], requiredKeywordArgumentsCount = 0, hasKeywordsRest = false}, originName = block in , blockDepth = 1, parseName = block in , notes = , argumentDescriptors = [ArgumentDescriptor(name = %for_0, type = req)]) - split = HEURISTIC - children: - body = - SequenceNode - attributes: - flags = 12 - children: - body = [ - WriteLocalVariableNode - attributes: - flags = 0 - frameSlot = 0 # (self) - children: - valueNode = - ProfileArgumentNodeGen - attributes: - flags = 0 - children: - childNode_ = - ReadSelfNode - attributes: - flags = 0 - WriteLocalVariableNode - attributes: - flags = 0 - frameSlot = 1 # %for_0 - children: - valueNode = - ProfileArgumentNodeGen - attributes: - flags = 0 - children: - childNode_ = - ReadPreArgumentNode - attributes: - flags = 0 - index = 0 - keywordArguments = false - missingArgumentBehavior = NIL - WriteDeclarationVariableNode - attributes: - flags = 0 - frameDepth = 1 - frameSlot = 4 - children: - valueNode = - ReadLocalVariableNode - attributes: - flags = 0 - frameSlot = 1 # %for_0 - type = FRAME_LOCAL - WriteDeclarationVariableNode - attributes: - flags = 1 - frameDepth = 1 - frameSlot = 5 - children: - valueNode = - IntegerFixnumLiteralNode - attributes: - flags = 0 - value = 1 - ] - receiver = - ArrayLiteralNode$UninitialisedArrayLiteralNode - attributes: - flags = 0 - language = org.truffleruby.RubyLanguage@... - children: - values = [ - IntegerFixnumLiteralNode - attributes: - flags = 0 - value = 42 - IntegerFixnumLiteralNode - attributes: - flags = 0 - value = 100500 - ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/reading.yaml b/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/reading.yaml index 8968059984be..476a9ff38421 100644 --- a/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/reading.yaml +++ b/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/reading.yaml @@ -57,6 +57,6 @@ ast: | attributes: flags = 1 frameDepth = 1 - frameSlot = 2 + frameSlot = 2 # foo type = FRAME_LOCAL ] \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/writing.yaml b/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/writing.yaml index 79132efffe5a..f65fbf652a63 100644 --- a/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/writing.yaml +++ b/spec/truffle/parsing/fixtures/local_variables/in_block_defined_in_outer_scope/writing.yaml @@ -62,7 +62,7 @@ ast: | attributes: flags = 1 frameDepth = 1 - frameSlot = 2 + frameSlot = 2 # foo children: valueNode = IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/operators/&&=/reference_assignment_with_explicit_self_receiver.yaml b/spec/truffle/parsing/fixtures/operators/&&=/reference_assignment_with_explicit_self_receiver.yaml index 38d9da56e6db..c4699a46ca86 100644 --- a/spec/truffle/parsing/fixtures/operators/&&=/reference_assignment_with_explicit_self_receiver.yaml +++ b/spec/truffle/parsing/fixtures/operators/&&=/reference_assignment_with_explicit_self_receiver.yaml @@ -3,8 +3,7 @@ description: "Assign an referenced element with explicit self receiver (self[a] notes: > Method call when receiver is `self` means a private or protected method could be successfully called. - In AST it's represented with RubyCallNode's field dispatchConfig. - `dispatchConfig = PRIVATE` means a method visibility is ignored. + In AST it's represented with method call parameter `ignoreVisibility=true`. yarp_specific: true # don't put self into a local variable and fixed call node and set ignoreVisibility=true focused_on_node: "org.truffleruby.language.control.SequenceNode" ruby: | diff --git a/spec/truffle/parsing/fixtures/operators/+=/reference_assignment_with_explicit_self_receiver.yaml b/spec/truffle/parsing/fixtures/operators/+=/reference_assignment_with_explicit_self_receiver.yaml index 70e8f960f440..999c6c6ab90a 100644 --- a/spec/truffle/parsing/fixtures/operators/+=/reference_assignment_with_explicit_self_receiver.yaml +++ b/spec/truffle/parsing/fixtures/operators/+=/reference_assignment_with_explicit_self_receiver.yaml @@ -3,8 +3,7 @@ description: "Assign a referenced element with explicit self receiver (self[a] + notes: > Method call when receiver is `self` means a private or protected method could be successfully called. - In AST it's represented with RubyCallNode's field dispatchConfig. - `dispatchConfig = PRIVATE` means a method visibility is ignored. + In AST it's represented with method call parameter `ignoreVisibility=true`. yarp_specific: true # don't put self into a local variable and fixed call node and set ignoreVisibility=true focused_on_node: "org.truffleruby.language.control.SequenceNode" ruby: | diff --git a/spec/truffle/parsing/fixtures/operators/multi_assignments/when_implicit_rest.yaml b/spec/truffle/parsing/fixtures/operators/multi_assignments/when_implicit_rest.yaml new file mode 100644 index 000000000000..d7f4bd70ac8f --- /dev/null +++ b/spec/truffle/parsing/fixtures/operators/multi_assignments/when_implicit_rest.yaml @@ -0,0 +1,29 @@ +subject: "Multi-assignment" +description: "When implicit rest (a, = [])" +notes: > + Implicit rest is just ignored +focused_on_node: "org.truffleruby.core.array.MultipleAssignmentNode" +ruby: | + a, = [] +ast: | + MultipleAssignmentNode + attributes: + flags = 1 + children: + preNodes = [ + WriteFrameSlotNodeGen + attributes: + frameSlot = 2 # a + ] + rhsNode = + ArrayLiteralNode$UninitialisedArrayLiteralNode + attributes: + flags = 0 + language = org.truffleruby.RubyLanguage@... + splatCastNode = + SplatCastNodeGen + attributes: + conversionMethod = :to_ary + copy = true + flags = 0 + nilBehavior = ARRAY_WITH_NIL \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_explicit_self_receiver.yaml b/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_explicit_self_receiver.yaml index fdfd3bcbe602..4c4c98fd5ec3 100644 --- a/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_explicit_self_receiver.yaml +++ b/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_explicit_self_receiver.yaml @@ -3,8 +3,7 @@ description: "Assign an referenced element with explicit self receiver (self[a] notes: > Method call when receiver is `self` means a private or protected method could be successfully called. - In AST it's represented with RubyCallNode's field dispatchConfig. - `dispatchConfig = PRIVATE` means a method visibility is ignored. + In AST it's represented with method call parameter `ignoreVisibility=true`. yarp_specific: true # don't put self into a local variable and fixed call node and set ignoreVisibility=true focused_on_node: "org.truffleruby.language.control.SequenceNode" ruby: | diff --git a/spec/truffle/parsing/fixtures/regexps/encoding/when_ascii_characters_only.yaml b/spec/truffle/parsing/fixtures/regexps/encoding/when_ascii_characters_only.yaml new file mode 100644 index 000000000000..97aa33093478 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding/when_ascii_characters_only.yaml @@ -0,0 +1,13 @@ +subject: "Regexp" +description: "encoding / when there are ASCII characters only in a literal" +notes: > + Regexp is forced to the US-ASCII encoding +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + # encoding: utf-8 + /abc/ +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: NONE, kcodeDefault, literal), encoding = US-ASCII) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding/when_non_ascii_characters.yaml b/spec/truffle/parsing/fixtures/regexps/encoding/when_non_ascii_characters.yaml new file mode 100644 index 000000000000..1fd3b14ed6db --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding/when_non_ascii_characters.yaml @@ -0,0 +1,13 @@ +subject: "Regexp" +description: "encoding / when there are non-ASCII characters in a literal" +notes: > + Regexp may be forced to the BINARY (ASCII-8BIT) encoding sometimes +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + # encoding: us-ascii + /abc \xFF/ +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc \xFF, options = RegexpOptions(kcode: NONE, fixed, kcodeDefault, literal), encoding = ASCII-8BIT) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding/when_utf8_characters.yaml b/spec/truffle/parsing/fixtures/regexps/encoding/when_utf8_characters.yaml new file mode 100644 index 000000000000..33c2737603b1 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding/when_utf8_characters.yaml @@ -0,0 +1,13 @@ +subject: "Regexp" +description: "encoding / when there are UTF-8 characters in a literal" +notes: > + Regexp may be forced to the UTF-8 encoding sometimes +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + # encoding: us-ascii + /abc \u{A3}/ +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc \u{A3}, options = RegexpOptions(kcode: NONE, fixed, kcodeDefault, literal), encoding = UTF-8) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_ascii_characters_only.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_ascii_characters_only.yaml new file mode 100644 index 000000000000..ecdb330544ec --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_ascii_characters_only.yaml @@ -0,0 +1,41 @@ +subject: "Regexp" +description: "encoding in boolean context / when there are ASCII characters only in a literal" +notes: > + Regexp is forced to the US-ASCII encoding +focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" +ruby: | + # encoding: utf-8 + /abc/ ? 1 : 2 +ast: | + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "=~" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ReadGlobalVariableNodeGen + attributes: + flags = 0 + name = "$_" + children: + lookupGlobalVariableStorageNode = + LookupGlobalVariableStorageNodeGen + attributes: + index = -1 + name = "$_" + ] + receiver = + ObjectLiteralNode + attributes: + flags = 0 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: NONE, kcodeDefault, literal), encoding = US-ASCII) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_non_ascii_characters.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_non_ascii_characters.yaml new file mode 100644 index 000000000000..2ef8e61208d6 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_non_ascii_characters.yaml @@ -0,0 +1,41 @@ +subject: "Regexp" +description: "encoding in boolean context / when there are non-ASCII characters in a literal" +notes: > + Regexp may be forced to the BINARY (ASCII-8BIT) encoding sometimes +focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" +ruby: | + # encoding: us-ascii + /abc \xFF/ ? 1 : 2 +ast: | + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "=~" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ReadGlobalVariableNodeGen + attributes: + flags = 0 + name = "$_" + children: + lookupGlobalVariableStorageNode = + LookupGlobalVariableStorageNodeGen + attributes: + index = -1 + name = "$_" + ] + receiver = + ObjectLiteralNode + attributes: + flags = 0 + object = RubyRegexp(source = abc \xFF, options = RegexpOptions(kcode: NONE, fixed, kcodeDefault, literal), encoding = ASCII-8BIT) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_utf8_characters.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_utf8_characters.yaml new file mode 100644 index 000000000000..4e4847cb3ed0 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_in_boolean_context/when_utf8_characters.yaml @@ -0,0 +1,41 @@ +subject: "Regexp" +description: "encoding in boolean context / when there are UTF-8 characters in a literal" +notes: > + Regexp may be forced to the UTF-8 encoding sometimes +focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" +ruby: | + # encoding: us-ascii + /abc \u{A3}/ ? 1 : 2 +ast: | + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PROTECTED + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "=~" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + ReadGlobalVariableNodeGen + attributes: + flags = 0 + name = "$_" + children: + lookupGlobalVariableStorageNode = + LookupGlobalVariableStorageNodeGen + attributes: + index = -1 + name = "$_" + ] + receiver = + ObjectLiteralNode + attributes: + flags = 0 + object = RubyRegexp(source = abc \u{A3}, options = RegexpOptions(kcode: NONE, fixed, kcodeDefault, literal), encoding = UTF-8) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_options/with_e_option.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_e_option.yaml new file mode 100644 index 000000000000..2e9250b710ae --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_e_option.yaml @@ -0,0 +1,12 @@ +subject: "Regexp" +description: "encoding options / with e option" +note: > + The 'e' modifiers overrides source encoding with EUC-JP encoding +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + /abc/e +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: EUC, fixed, literal), encoding = EUC-JP) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_options/with_n_option.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_n_option.yaml new file mode 100644 index 000000000000..8e1babe9edb7 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_n_option.yaml @@ -0,0 +1,13 @@ +subject: "Regexp" +description: "encoding options / with n option" +note: > + The 'n' modifiers overrides source encoding with US-ASCII encoding. + According to the documentation it should be ASCII-8BIT encoding actually. +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + /abc/n +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: NONE, encodingNone, literal), encoding = US-ASCII) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_options/with_s_option.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_s_option.yaml new file mode 100644 index 000000000000..884a4d1d6c37 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_s_option.yaml @@ -0,0 +1,12 @@ +subject: "Regexp" +description: "encoding options / with s option" +note: > + The 's' modifiers overrides source encoding with Windows-31J encoding +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + /abc/s +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: SJIS, fixed, literal), encoding = Windows-31J) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/regexps/encoding_options/with_u_option.yaml b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_u_option.yaml new file mode 100644 index 000000000000..515c86262a97 --- /dev/null +++ b/spec/truffle/parsing/fixtures/regexps/encoding_options/with_u_option.yaml @@ -0,0 +1,12 @@ +subject: "Regexp" +description: "encoding options / with u option" +note: > + The 'u' modifiers overrides source encoding with UTF-8 encoding +focused_on_node: "org.truffleruby.language.literal.ObjectLiteralNode" +ruby: | + /abc/u +ast: | + ObjectLiteralNode + attributes: + flags = 1 + object = RubyRegexp(source = abc, options = RegexpOptions(kcode: UTF8, fixed, literal), encoding = UTF-8) \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml index 6e771fcaad5a..152d238c3075 100644 --- a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml +++ b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml @@ -73,7 +73,7 @@ ast: | attributes: flags = 1 frameDepth = 1 - frameSlot = 2 + frameSlot = 2 # bar type = FRAME_LOCAL ] tryPart = diff --git a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml index 8132dbe47098..3b9bba84266e 100644 --- a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml +++ b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_local_variable_defined_in_outer_scope.yaml @@ -71,7 +71,7 @@ ast: | attributes: flags = 0 frameDepth = 1 - frameSlot = 2 + frameSlot = 2 # bar type = FRAME_LOCAL ] tryPart = diff --git a/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml b/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml index f4a9a95658f4..106a918088d2 100644 --- a/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml +++ b/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml @@ -23,11 +23,11 @@ ast: | notRuby2KeywordsHashProfile = false children: arguments = [ - StringLiteralNode + FrozenStringLiteralNode attributes: - encoding = UTF-8 + definition = expression flags = 0 - tstring = echo 1 + frozenString = echo 1 ] receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/strings/encoding/when_non_ascii_characters.yaml b/spec/truffle/parsing/fixtures/strings/encoding/when_non_ascii_characters.yaml new file mode 100644 index 000000000000..ab58511abe05 --- /dev/null +++ b/spec/truffle/parsing/fixtures/strings/encoding/when_non_ascii_characters.yaml @@ -0,0 +1,14 @@ +subject: "String" +description: "encoding / when there are ASCII and non-ASCII characters in a literal" +notes: > + String may be forced to the BINARY (ASCII-8BIT) encoding sometimes +focused_on_node: "org.truffleruby.language.literal.StringLiteralNode" +ruby: | + # encoding: us-ascii + "\xFF" +ast: | + StringLiteralNode + attributes: + encoding = ASCII-8BIT + flags = 1 + tstring = \xFF \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/strings/encoding/when_utf8_characters.yaml b/spec/truffle/parsing/fixtures/strings/encoding/when_utf8_characters.yaml new file mode 100644 index 000000000000..f157fab5e977 --- /dev/null +++ b/spec/truffle/parsing/fixtures/strings/encoding/when_utf8_characters.yaml @@ -0,0 +1,14 @@ +subject: "String" +description: "encoding / when there are UTF-8 characters in a literal" +notes: > + String may be forced to the UTF-8 encoding sometimes +focused_on_node: "org.truffleruby.language.literal.StringLiteralNode" +ruby: | + # encoding: us-ascii + "\u{A3}" +ast: | + StringLiteralNode + attributes: + encoding = UTF-8 + flags = 1 + tstring = £ \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_non_ascii_characters.yaml b/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_non_ascii_characters.yaml new file mode 100644 index 000000000000..debcfb151153 --- /dev/null +++ b/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_non_ascii_characters.yaml @@ -0,0 +1,35 @@ +subject: "String" +description: "backtick literal / encoding / when there are ASCII and non-ASCII characters" +notes: > + String may be forced to the BINARY (ASCII-8BIT) encoding sometimes +focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" +ruby: | + # encoding: us-ascii + `echo \xFF 1` +ast: | + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "`" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + FrozenStringLiteralNode + attributes: + definition = expression + flags = 0 + frozenString = echo \xFF 1 + ] + receiver = + SelfNode + attributes: + flags = 0 \ No newline at end of file diff --git a/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_utf8_characters.yaml b/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_utf8_characters.yaml new file mode 100644 index 000000000000..e7acc95e99b7 --- /dev/null +++ b/spec/truffle/parsing/fixtures/strings/encoding_of_backtick_literal/when_utf8_characters.yaml @@ -0,0 +1,35 @@ +subject: "String" +description: "backtick literal / encoding / when there are UTF-8 characters in a literal" +notes: > + String may be forced to the UTF-8 encoding sometimes +focused_on_node: "org.truffleruby.language.dispatch.RubyCallNode" +ruby: | + # encoding: us-ascii + `echo \u{A3} 1` +ast: | + RubyCallNode + attributes: + descriptor = NoKeywordArgumentsDescriptor + dispatchConfig = PRIVATE + emptyKeywordsProfile = false + flags = 1 + isAttrAssign = false + isSafeNavigation = false + isSplatted = false + isVCall = false + lastArgIsNotHashProfile = false + methodName = "`" + notEmptyKeywordsProfile = false + notRuby2KeywordsHashProfile = false + children: + arguments = [ + FrozenStringLiteralNode + attributes: + definition = expression + flags = 0 + frozenString = echo £ 1 + ] + receiver = + SelfNode + attributes: + flags = 0 \ No newline at end of file diff --git a/src/main/c/yarp/include/prism.h b/src/main/c/yarp/include/prism.h index 590cd740168b..f4a248274fcd 100644 --- a/src/main/c/yarp/include/prism.h +++ b/src/main/c/yarp/include/prism.h @@ -91,7 +91,7 @@ void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t * @param encoding The encoding to serialize. * @param buffer The buffer to serialize to. */ -void pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer); +void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer); /** * Serialize the encoding, metadata, nodes, and constant pool. @@ -211,7 +211,7 @@ PRISM_EXPORTED_FUNCTION const char * pm_token_type_to_str(pm_token_type_t token_ * pm_node_t *root = pm_parse(&parser); * printf("PARSED!\n"); * - * pm_node_destroy(root); + * pm_node_destroy(&parser, root); * pm_parser_free(&parser); * } * ``` @@ -260,10 +260,10 @@ PRISM_EXPORTED_FUNCTION const char * pm_token_type_to_str(pm_token_type_t token_ * pm_buffer_t buffer = { 0 }; * * pm_prettyprint(&buffer, &parser, root); - * printf("*.s%\n", (int) buffer.length, buffer.value); + * printf("%*.s\n", (int) buffer.length, buffer.value); * * pm_buffer_free(&buffer); - * pm_node_destroy(root); + * pm_node_destroy(&parser, root); * pm_parser_free(&parser); * } * ``` diff --git a/src/main/c/yarp/include/prism/ast.h b/src/main/c/yarp/include/prism/ast.h index 810da26d0733..bcbcb8164565 100644 --- a/src/main/c/yarp/include/prism/ast.h +++ b/src/main/c/yarp/include/prism/ast.h @@ -631,380 +631,386 @@ enum pm_node_type { /** CallOrWriteNode */ PM_CALL_OR_WRITE_NODE = 21, + /** CallTargetNode */ + PM_CALL_TARGET_NODE = 22, + /** CapturePatternNode */ - PM_CAPTURE_PATTERN_NODE = 22, + PM_CAPTURE_PATTERN_NODE = 23, /** CaseMatchNode */ - PM_CASE_MATCH_NODE = 23, + PM_CASE_MATCH_NODE = 24, /** CaseNode */ - PM_CASE_NODE = 24, + PM_CASE_NODE = 25, /** ClassNode */ - PM_CLASS_NODE = 25, + PM_CLASS_NODE = 26, /** ClassVariableAndWriteNode */ - PM_CLASS_VARIABLE_AND_WRITE_NODE = 26, + PM_CLASS_VARIABLE_AND_WRITE_NODE = 27, /** ClassVariableOperatorWriteNode */ - PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE = 27, + PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE = 28, /** ClassVariableOrWriteNode */ - PM_CLASS_VARIABLE_OR_WRITE_NODE = 28, + PM_CLASS_VARIABLE_OR_WRITE_NODE = 29, /** ClassVariableReadNode */ - PM_CLASS_VARIABLE_READ_NODE = 29, + PM_CLASS_VARIABLE_READ_NODE = 30, /** ClassVariableTargetNode */ - PM_CLASS_VARIABLE_TARGET_NODE = 30, + PM_CLASS_VARIABLE_TARGET_NODE = 31, /** ClassVariableWriteNode */ - PM_CLASS_VARIABLE_WRITE_NODE = 31, + PM_CLASS_VARIABLE_WRITE_NODE = 32, /** ConstantAndWriteNode */ - PM_CONSTANT_AND_WRITE_NODE = 32, + PM_CONSTANT_AND_WRITE_NODE = 33, /** ConstantOperatorWriteNode */ - PM_CONSTANT_OPERATOR_WRITE_NODE = 33, + PM_CONSTANT_OPERATOR_WRITE_NODE = 34, /** ConstantOrWriteNode */ - PM_CONSTANT_OR_WRITE_NODE = 34, + PM_CONSTANT_OR_WRITE_NODE = 35, /** ConstantPathAndWriteNode */ - PM_CONSTANT_PATH_AND_WRITE_NODE = 35, + PM_CONSTANT_PATH_AND_WRITE_NODE = 36, /** ConstantPathNode */ - PM_CONSTANT_PATH_NODE = 36, + PM_CONSTANT_PATH_NODE = 37, /** ConstantPathOperatorWriteNode */ - PM_CONSTANT_PATH_OPERATOR_WRITE_NODE = 37, + PM_CONSTANT_PATH_OPERATOR_WRITE_NODE = 38, /** ConstantPathOrWriteNode */ - PM_CONSTANT_PATH_OR_WRITE_NODE = 38, + PM_CONSTANT_PATH_OR_WRITE_NODE = 39, /** ConstantPathTargetNode */ - PM_CONSTANT_PATH_TARGET_NODE = 39, + PM_CONSTANT_PATH_TARGET_NODE = 40, /** ConstantPathWriteNode */ - PM_CONSTANT_PATH_WRITE_NODE = 40, + PM_CONSTANT_PATH_WRITE_NODE = 41, /** ConstantReadNode */ - PM_CONSTANT_READ_NODE = 41, + PM_CONSTANT_READ_NODE = 42, /** ConstantTargetNode */ - PM_CONSTANT_TARGET_NODE = 42, + PM_CONSTANT_TARGET_NODE = 43, /** ConstantWriteNode */ - PM_CONSTANT_WRITE_NODE = 43, + PM_CONSTANT_WRITE_NODE = 44, /** DefNode */ - PM_DEF_NODE = 44, + PM_DEF_NODE = 45, /** DefinedNode */ - PM_DEFINED_NODE = 45, + PM_DEFINED_NODE = 46, /** ElseNode */ - PM_ELSE_NODE = 46, + PM_ELSE_NODE = 47, /** EmbeddedStatementsNode */ - PM_EMBEDDED_STATEMENTS_NODE = 47, + PM_EMBEDDED_STATEMENTS_NODE = 48, /** EmbeddedVariableNode */ - PM_EMBEDDED_VARIABLE_NODE = 48, + PM_EMBEDDED_VARIABLE_NODE = 49, /** EnsureNode */ - PM_ENSURE_NODE = 49, + PM_ENSURE_NODE = 50, /** FalseNode */ - PM_FALSE_NODE = 50, + PM_FALSE_NODE = 51, /** FindPatternNode */ - PM_FIND_PATTERN_NODE = 51, + PM_FIND_PATTERN_NODE = 52, /** FlipFlopNode */ - PM_FLIP_FLOP_NODE = 52, + PM_FLIP_FLOP_NODE = 53, /** FloatNode */ - PM_FLOAT_NODE = 53, + PM_FLOAT_NODE = 54, /** ForNode */ - PM_FOR_NODE = 54, + PM_FOR_NODE = 55, /** ForwardingArgumentsNode */ - PM_FORWARDING_ARGUMENTS_NODE = 55, + PM_FORWARDING_ARGUMENTS_NODE = 56, /** ForwardingParameterNode */ - PM_FORWARDING_PARAMETER_NODE = 56, + PM_FORWARDING_PARAMETER_NODE = 57, /** ForwardingSuperNode */ - PM_FORWARDING_SUPER_NODE = 57, + PM_FORWARDING_SUPER_NODE = 58, /** GlobalVariableAndWriteNode */ - PM_GLOBAL_VARIABLE_AND_WRITE_NODE = 58, + PM_GLOBAL_VARIABLE_AND_WRITE_NODE = 59, /** GlobalVariableOperatorWriteNode */ - PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE = 59, + PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE = 60, /** GlobalVariableOrWriteNode */ - PM_GLOBAL_VARIABLE_OR_WRITE_NODE = 60, + PM_GLOBAL_VARIABLE_OR_WRITE_NODE = 61, /** GlobalVariableReadNode */ - PM_GLOBAL_VARIABLE_READ_NODE = 61, + PM_GLOBAL_VARIABLE_READ_NODE = 62, /** GlobalVariableTargetNode */ - PM_GLOBAL_VARIABLE_TARGET_NODE = 62, + PM_GLOBAL_VARIABLE_TARGET_NODE = 63, /** GlobalVariableWriteNode */ - PM_GLOBAL_VARIABLE_WRITE_NODE = 63, + PM_GLOBAL_VARIABLE_WRITE_NODE = 64, /** HashNode */ - PM_HASH_NODE = 64, + PM_HASH_NODE = 65, /** HashPatternNode */ - PM_HASH_PATTERN_NODE = 65, + PM_HASH_PATTERN_NODE = 66, /** IfNode */ - PM_IF_NODE = 66, + PM_IF_NODE = 67, /** ImaginaryNode */ - PM_IMAGINARY_NODE = 67, + PM_IMAGINARY_NODE = 68, /** ImplicitNode */ - PM_IMPLICIT_NODE = 68, + PM_IMPLICIT_NODE = 69, /** ImplicitRestNode */ - PM_IMPLICIT_REST_NODE = 69, + PM_IMPLICIT_REST_NODE = 70, /** InNode */ - PM_IN_NODE = 70, + PM_IN_NODE = 71, /** IndexAndWriteNode */ - PM_INDEX_AND_WRITE_NODE = 71, + PM_INDEX_AND_WRITE_NODE = 72, /** IndexOperatorWriteNode */ - PM_INDEX_OPERATOR_WRITE_NODE = 72, + PM_INDEX_OPERATOR_WRITE_NODE = 73, /** IndexOrWriteNode */ - PM_INDEX_OR_WRITE_NODE = 73, + PM_INDEX_OR_WRITE_NODE = 74, + + /** IndexTargetNode */ + PM_INDEX_TARGET_NODE = 75, /** InstanceVariableAndWriteNode */ - PM_INSTANCE_VARIABLE_AND_WRITE_NODE = 74, + PM_INSTANCE_VARIABLE_AND_WRITE_NODE = 76, /** InstanceVariableOperatorWriteNode */ - PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE = 75, + PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE = 77, /** InstanceVariableOrWriteNode */ - PM_INSTANCE_VARIABLE_OR_WRITE_NODE = 76, + PM_INSTANCE_VARIABLE_OR_WRITE_NODE = 78, /** InstanceVariableReadNode */ - PM_INSTANCE_VARIABLE_READ_NODE = 77, + PM_INSTANCE_VARIABLE_READ_NODE = 79, /** InstanceVariableTargetNode */ - PM_INSTANCE_VARIABLE_TARGET_NODE = 78, + PM_INSTANCE_VARIABLE_TARGET_NODE = 80, /** InstanceVariableWriteNode */ - PM_INSTANCE_VARIABLE_WRITE_NODE = 79, + PM_INSTANCE_VARIABLE_WRITE_NODE = 81, /** IntegerNode */ - PM_INTEGER_NODE = 80, + PM_INTEGER_NODE = 82, /** InterpolatedMatchLastLineNode */ - PM_INTERPOLATED_MATCH_LAST_LINE_NODE = 81, + PM_INTERPOLATED_MATCH_LAST_LINE_NODE = 83, /** InterpolatedRegularExpressionNode */ - PM_INTERPOLATED_REGULAR_EXPRESSION_NODE = 82, + PM_INTERPOLATED_REGULAR_EXPRESSION_NODE = 84, /** InterpolatedStringNode */ - PM_INTERPOLATED_STRING_NODE = 83, + PM_INTERPOLATED_STRING_NODE = 85, /** InterpolatedSymbolNode */ - PM_INTERPOLATED_SYMBOL_NODE = 84, + PM_INTERPOLATED_SYMBOL_NODE = 86, /** InterpolatedXStringNode */ - PM_INTERPOLATED_X_STRING_NODE = 85, + PM_INTERPOLATED_X_STRING_NODE = 87, /** KeywordHashNode */ - PM_KEYWORD_HASH_NODE = 86, + PM_KEYWORD_HASH_NODE = 88, /** KeywordRestParameterNode */ - PM_KEYWORD_REST_PARAMETER_NODE = 87, + PM_KEYWORD_REST_PARAMETER_NODE = 89, /** LambdaNode */ - PM_LAMBDA_NODE = 88, + PM_LAMBDA_NODE = 90, /** LocalVariableAndWriteNode */ - PM_LOCAL_VARIABLE_AND_WRITE_NODE = 89, + PM_LOCAL_VARIABLE_AND_WRITE_NODE = 91, /** LocalVariableOperatorWriteNode */ - PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE = 90, + PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE = 92, /** LocalVariableOrWriteNode */ - PM_LOCAL_VARIABLE_OR_WRITE_NODE = 91, + PM_LOCAL_VARIABLE_OR_WRITE_NODE = 93, /** LocalVariableReadNode */ - PM_LOCAL_VARIABLE_READ_NODE = 92, + PM_LOCAL_VARIABLE_READ_NODE = 94, /** LocalVariableTargetNode */ - PM_LOCAL_VARIABLE_TARGET_NODE = 93, + PM_LOCAL_VARIABLE_TARGET_NODE = 95, /** LocalVariableWriteNode */ - PM_LOCAL_VARIABLE_WRITE_NODE = 94, + PM_LOCAL_VARIABLE_WRITE_NODE = 96, /** MatchLastLineNode */ - PM_MATCH_LAST_LINE_NODE = 95, + PM_MATCH_LAST_LINE_NODE = 97, /** MatchPredicateNode */ - PM_MATCH_PREDICATE_NODE = 96, + PM_MATCH_PREDICATE_NODE = 98, /** MatchRequiredNode */ - PM_MATCH_REQUIRED_NODE = 97, + PM_MATCH_REQUIRED_NODE = 99, /** MatchWriteNode */ - PM_MATCH_WRITE_NODE = 98, + PM_MATCH_WRITE_NODE = 100, /** MissingNode */ - PM_MISSING_NODE = 99, + PM_MISSING_NODE = 101, /** ModuleNode */ - PM_MODULE_NODE = 100, + PM_MODULE_NODE = 102, /** MultiTargetNode */ - PM_MULTI_TARGET_NODE = 101, + PM_MULTI_TARGET_NODE = 103, /** MultiWriteNode */ - PM_MULTI_WRITE_NODE = 102, + PM_MULTI_WRITE_NODE = 104, /** NextNode */ - PM_NEXT_NODE = 103, + PM_NEXT_NODE = 105, /** NilNode */ - PM_NIL_NODE = 104, + PM_NIL_NODE = 106, /** NoKeywordsParameterNode */ - PM_NO_KEYWORDS_PARAMETER_NODE = 105, + PM_NO_KEYWORDS_PARAMETER_NODE = 107, /** NumberedParametersNode */ - PM_NUMBERED_PARAMETERS_NODE = 106, + PM_NUMBERED_PARAMETERS_NODE = 108, /** NumberedReferenceReadNode */ - PM_NUMBERED_REFERENCE_READ_NODE = 107, + PM_NUMBERED_REFERENCE_READ_NODE = 109, /** OptionalKeywordParameterNode */ - PM_OPTIONAL_KEYWORD_PARAMETER_NODE = 108, + PM_OPTIONAL_KEYWORD_PARAMETER_NODE = 110, /** OptionalParameterNode */ - PM_OPTIONAL_PARAMETER_NODE = 109, + PM_OPTIONAL_PARAMETER_NODE = 111, /** OrNode */ - PM_OR_NODE = 110, + PM_OR_NODE = 112, /** ParametersNode */ - PM_PARAMETERS_NODE = 111, + PM_PARAMETERS_NODE = 113, /** ParenthesesNode */ - PM_PARENTHESES_NODE = 112, + PM_PARENTHESES_NODE = 114, /** PinnedExpressionNode */ - PM_PINNED_EXPRESSION_NODE = 113, + PM_PINNED_EXPRESSION_NODE = 115, /** PinnedVariableNode */ - PM_PINNED_VARIABLE_NODE = 114, + PM_PINNED_VARIABLE_NODE = 116, /** PostExecutionNode */ - PM_POST_EXECUTION_NODE = 115, + PM_POST_EXECUTION_NODE = 117, /** PreExecutionNode */ - PM_PRE_EXECUTION_NODE = 116, + PM_PRE_EXECUTION_NODE = 118, /** ProgramNode */ - PM_PROGRAM_NODE = 117, + PM_PROGRAM_NODE = 119, /** RangeNode */ - PM_RANGE_NODE = 118, + PM_RANGE_NODE = 120, /** RationalNode */ - PM_RATIONAL_NODE = 119, + PM_RATIONAL_NODE = 121, /** RedoNode */ - PM_REDO_NODE = 120, + PM_REDO_NODE = 122, /** RegularExpressionNode */ - PM_REGULAR_EXPRESSION_NODE = 121, + PM_REGULAR_EXPRESSION_NODE = 123, /** RequiredKeywordParameterNode */ - PM_REQUIRED_KEYWORD_PARAMETER_NODE = 122, + PM_REQUIRED_KEYWORD_PARAMETER_NODE = 124, /** RequiredParameterNode */ - PM_REQUIRED_PARAMETER_NODE = 123, + PM_REQUIRED_PARAMETER_NODE = 125, /** RescueModifierNode */ - PM_RESCUE_MODIFIER_NODE = 124, + PM_RESCUE_MODIFIER_NODE = 126, /** RescueNode */ - PM_RESCUE_NODE = 125, + PM_RESCUE_NODE = 127, /** RestParameterNode */ - PM_REST_PARAMETER_NODE = 126, + PM_REST_PARAMETER_NODE = 128, /** RetryNode */ - PM_RETRY_NODE = 127, + PM_RETRY_NODE = 129, /** ReturnNode */ - PM_RETURN_NODE = 128, + PM_RETURN_NODE = 130, /** SelfNode */ - PM_SELF_NODE = 129, + PM_SELF_NODE = 131, /** SingletonClassNode */ - PM_SINGLETON_CLASS_NODE = 130, + PM_SINGLETON_CLASS_NODE = 132, /** SourceEncodingNode */ - PM_SOURCE_ENCODING_NODE = 131, + PM_SOURCE_ENCODING_NODE = 133, /** SourceFileNode */ - PM_SOURCE_FILE_NODE = 132, + PM_SOURCE_FILE_NODE = 134, /** SourceLineNode */ - PM_SOURCE_LINE_NODE = 133, + PM_SOURCE_LINE_NODE = 135, /** SplatNode */ - PM_SPLAT_NODE = 134, + PM_SPLAT_NODE = 136, /** StatementsNode */ - PM_STATEMENTS_NODE = 135, + PM_STATEMENTS_NODE = 137, /** StringNode */ - PM_STRING_NODE = 136, + PM_STRING_NODE = 138, /** SuperNode */ - PM_SUPER_NODE = 137, + PM_SUPER_NODE = 139, /** SymbolNode */ - PM_SYMBOL_NODE = 138, + PM_SYMBOL_NODE = 140, /** TrueNode */ - PM_TRUE_NODE = 139, + PM_TRUE_NODE = 141, /** UndefNode */ - PM_UNDEF_NODE = 140, + PM_UNDEF_NODE = 142, /** UnlessNode */ - PM_UNLESS_NODE = 141, + PM_UNLESS_NODE = 143, /** UntilNode */ - PM_UNTIL_NODE = 142, + PM_UNTIL_NODE = 144, /** WhenNode */ - PM_WHEN_NODE = 143, + PM_WHEN_NODE = 145, /** WhileNode */ - PM_WHILE_NODE = 144, + PM_WHILE_NODE = 146, /** XStringNode */ - PM_X_STRING_NODE = 145, + PM_X_STRING_NODE = 147, /** YieldNode */ - PM_YIELD_NODE = 146, + PM_YIELD_NODE = 148, /** A special kind of node used for compilation. */ PM_SCOPE_NODE @@ -1043,6 +1049,11 @@ static const pm_node_flags_t PM_NODE_FLAG_COMMON_MASK = (1 << (PM_NODE_FLAG_BITS */ #define PM_NODE_TYPE_P(node, type) (PM_NODE_TYPE(node) == (type)) +/** + * Return true if the given flag is set on the given node. + */ +#define PM_NODE_FLAG_P(node, flag) ((((pm_node_t *)(node))->flags & (flag)) != 0) + /** * This is the base structure that represents a node in the syntax tree. It is * embedded into every node type. @@ -1078,13 +1089,19 @@ typedef struct pm_alias_global_variable_node { /** The embedded base node. */ pm_node_t base; - /** AliasGlobalVariableNode#new_name */ + /** + * AliasGlobalVariableNode#new_name + */ struct pm_node *new_name; - /** AliasGlobalVariableNode#old_name */ + /** + * AliasGlobalVariableNode#old_name + */ struct pm_node *old_name; - /** AliasGlobalVariableNode#keyword_loc */ + /** + * AliasGlobalVariableNode#keyword_loc + */ pm_location_t keyword_loc; } pm_alias_global_variable_node_t; @@ -1099,13 +1116,19 @@ typedef struct pm_alias_method_node { /** The embedded base node. */ pm_node_t base; - /** AliasMethodNode#new_name */ + /** + * AliasMethodNode#new_name + */ struct pm_node *new_name; - /** AliasMethodNode#old_name */ + /** + * AliasMethodNode#old_name + */ struct pm_node *old_name; - /** AliasMethodNode#keyword_loc */ + /** + * AliasMethodNode#keyword_loc + */ pm_location_t keyword_loc; } pm_alias_method_node_t; @@ -1120,13 +1143,19 @@ typedef struct pm_alternation_pattern_node { /** The embedded base node. */ pm_node_t base; - /** AlternationPatternNode#left */ + /** + * AlternationPatternNode#left + */ struct pm_node *left; - /** AlternationPatternNode#right */ + /** + * AlternationPatternNode#right + */ struct pm_node *right; - /** AlternationPatternNode#operator_loc */ + /** + * AlternationPatternNode#operator_loc + */ pm_location_t operator_loc; } pm_alternation_pattern_node_t; @@ -1141,13 +1170,19 @@ typedef struct pm_and_node { /** The embedded base node. */ pm_node_t base; - /** AndNode#left */ + /** + * AndNode#left + */ struct pm_node *left; - /** AndNode#right */ + /** + * AndNode#right + */ struct pm_node *right; - /** AndNode#operator_loc */ + /** + * AndNode#operator_loc + */ pm_location_t operator_loc; } pm_and_node_t; @@ -1164,7 +1199,9 @@ typedef struct pm_arguments_node { /** The embedded base node. */ pm_node_t base; - /** ArgumentsNode#arguments */ + /** + * ArgumentsNode#arguments + */ struct pm_node_list arguments; } pm_arguments_node_t; @@ -1181,13 +1218,19 @@ typedef struct pm_array_node { /** The embedded base node. */ pm_node_t base; - /** ArrayNode#elements */ + /** + * ArrayNode#elements + */ struct pm_node_list elements; - /** ArrayNode#opening_loc */ + /** + * ArrayNode#opening_loc + */ pm_location_t opening_loc; - /** ArrayNode#closing_loc */ + /** + * ArrayNode#closing_loc + */ pm_location_t closing_loc; } pm_array_node_t; @@ -1202,22 +1245,34 @@ typedef struct pm_array_pattern_node { /** The embedded base node. */ pm_node_t base; - /** ArrayPatternNode#constant */ + /** + * ArrayPatternNode#constant + */ struct pm_node *constant; - /** ArrayPatternNode#requireds */ + /** + * ArrayPatternNode#requireds + */ struct pm_node_list requireds; - /** ArrayPatternNode#rest */ + /** + * ArrayPatternNode#rest + */ struct pm_node *rest; - /** ArrayPatternNode#posts */ + /** + * ArrayPatternNode#posts + */ struct pm_node_list posts; - /** ArrayPatternNode#opening_loc */ + /** + * ArrayPatternNode#opening_loc + */ pm_location_t opening_loc; - /** ArrayPatternNode#closing_loc */ + /** + * ArrayPatternNode#closing_loc + */ pm_location_t closing_loc; } pm_array_pattern_node_t; @@ -1232,13 +1287,19 @@ typedef struct pm_assoc_node { /** The embedded base node. */ pm_node_t base; - /** AssocNode#key */ + /** + * AssocNode#key + */ struct pm_node *key; - /** AssocNode#value */ + /** + * AssocNode#value + */ struct pm_node *value; - /** AssocNode#operator_loc */ + /** + * AssocNode#operator_loc + */ pm_location_t operator_loc; } pm_assoc_node_t; @@ -1253,10 +1314,14 @@ typedef struct pm_assoc_splat_node { /** The embedded base node. */ pm_node_t base; - /** AssocSplatNode#value */ + /** + * AssocSplatNode#value + */ struct pm_node *value; - /** AssocSplatNode#operator_loc */ + /** + * AssocSplatNode#operator_loc + */ pm_location_t operator_loc; } pm_assoc_splat_node_t; @@ -1271,7 +1336,9 @@ typedef struct pm_back_reference_read_node { /** The embedded base node. */ pm_node_t base; - /** BackReferenceReadNode#name */ + /** + * BackReferenceReadNode#name + */ pm_constant_id_t name; } pm_back_reference_read_node_t; @@ -1286,22 +1353,34 @@ typedef struct pm_begin_node { /** The embedded base node. */ pm_node_t base; - /** BeginNode#begin_keyword_loc */ + /** + * BeginNode#begin_keyword_loc + */ pm_location_t begin_keyword_loc; - /** BeginNode#statements */ + /** + * BeginNode#statements + */ struct pm_statements_node *statements; - /** BeginNode#rescue_clause */ + /** + * BeginNode#rescue_clause + */ struct pm_rescue_node *rescue_clause; - /** BeginNode#else_clause */ + /** + * BeginNode#else_clause + */ struct pm_else_node *else_clause; - /** BeginNode#ensure_clause */ + /** + * BeginNode#ensure_clause + */ struct pm_ensure_node *ensure_clause; - /** BeginNode#end_keyword_loc */ + /** + * BeginNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_begin_node_t; @@ -1316,10 +1395,14 @@ typedef struct pm_block_argument_node { /** The embedded base node. */ pm_node_t base; - /** BlockArgumentNode#expression */ + /** + * BlockArgumentNode#expression + */ struct pm_node *expression; - /** BlockArgumentNode#operator_loc */ + /** + * BlockArgumentNode#operator_loc + */ pm_location_t operator_loc; } pm_block_argument_node_t; @@ -1334,7 +1417,9 @@ typedef struct pm_block_local_variable_node { /** The embedded base node. */ pm_node_t base; - /** BlockLocalVariableNode#name */ + /** + * BlockLocalVariableNode#name + */ pm_constant_id_t name; } pm_block_local_variable_node_t; @@ -1349,19 +1434,34 @@ typedef struct pm_block_node { /** The embedded base node. */ pm_node_t base; - /** BlockNode#locals */ + /** + * BlockNode#locals + */ pm_constant_id_list_t locals; - /** BlockNode#parameters */ + /** + * BlockNode#locals_body_index + */ + uint32_t locals_body_index; + + /** + * BlockNode#parameters + */ struct pm_node *parameters; - /** BlockNode#body */ + /** + * BlockNode#body + */ struct pm_node *body; - /** BlockNode#opening_loc */ + /** + * BlockNode#opening_loc + */ pm_location_t opening_loc; - /** BlockNode#closing_loc */ + /** + * BlockNode#closing_loc + */ pm_location_t closing_loc; } pm_block_node_t; @@ -1376,13 +1476,19 @@ typedef struct pm_block_parameter_node { /** The embedded base node. */ pm_node_t base; - /** BlockParameterNode#name */ + /** + * BlockParameterNode#name + */ pm_constant_id_t name; - /** BlockParameterNode#name_loc */ + /** + * BlockParameterNode#name_loc + */ pm_location_t name_loc; - /** BlockParameterNode#operator_loc */ + /** + * BlockParameterNode#operator_loc + */ pm_location_t operator_loc; } pm_block_parameter_node_t; @@ -1397,16 +1503,24 @@ typedef struct pm_block_parameters_node { /** The embedded base node. */ pm_node_t base; - /** BlockParametersNode#parameters */ + /** + * BlockParametersNode#parameters + */ struct pm_parameters_node *parameters; - /** BlockParametersNode#locals */ + /** + * BlockParametersNode#locals + */ struct pm_node_list locals; - /** BlockParametersNode#opening_loc */ + /** + * BlockParametersNode#opening_loc + */ pm_location_t opening_loc; - /** BlockParametersNode#closing_loc */ + /** + * BlockParametersNode#closing_loc + */ pm_location_t closing_loc; } pm_block_parameters_node_t; @@ -1421,10 +1535,14 @@ typedef struct pm_break_node { /** The embedded base node. */ pm_node_t base; - /** BreakNode#arguments */ + /** + * BreakNode#arguments + */ struct pm_arguments_node *arguments; - /** BreakNode#keyword_loc */ + /** + * BreakNode#keyword_loc + */ pm_location_t keyword_loc; } pm_break_node_t; @@ -1435,6 +1553,8 @@ typedef struct pm_break_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1442,25 +1562,39 @@ typedef struct pm_call_and_write_node { /** The embedded base node. */ pm_node_t base; - /** CallAndWriteNode#receiver */ + /** + * CallAndWriteNode#receiver + */ struct pm_node *receiver; - /** CallAndWriteNode#call_operator_loc */ + /** + * CallAndWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** CallAndWriteNode#message_loc */ + /** + * CallAndWriteNode#message_loc + */ pm_location_t message_loc; - /** CallAndWriteNode#read_name */ + /** + * CallAndWriteNode#read_name + */ pm_constant_id_t read_name; - /** CallAndWriteNode#write_name */ + /** + * CallAndWriteNode#write_name + */ pm_constant_id_t write_name; - /** CallAndWriteNode#operator_loc */ + /** + * CallAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** CallAndWriteNode#value */ + /** + * CallAndWriteNode#value + */ struct pm_node *value; } pm_call_and_write_node_t; @@ -1471,6 +1605,8 @@ typedef struct pm_call_and_write_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1478,28 +1614,57 @@ typedef struct pm_call_node { /** The embedded base node. */ pm_node_t base; - /** CallNode#receiver */ + /** + * CallNode#receiver + * + * The object that the method is being called on. This can be either + * `nil` or a node representing any kind of expression that returns a + * non-void value. + * + * foo.bar + * ^^^ + * + * +foo + * ^^^ + * + * foo + bar + * ^^^ + */ struct pm_node *receiver; - /** CallNode#call_operator_loc */ + /** + * CallNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** CallNode#name */ + /** + * CallNode#name + */ pm_constant_id_t name; - /** CallNode#message_loc */ + /** + * CallNode#message_loc + */ pm_location_t message_loc; - /** CallNode#opening_loc */ + /** + * CallNode#opening_loc + */ pm_location_t opening_loc; - /** CallNode#arguments */ + /** + * CallNode#arguments + */ struct pm_arguments_node *arguments; - /** CallNode#closing_loc */ + /** + * CallNode#closing_loc + */ pm_location_t closing_loc; - /** CallNode#block */ + /** + * CallNode#block + */ struct pm_node *block; } pm_call_node_t; @@ -1510,6 +1675,8 @@ typedef struct pm_call_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1517,28 +1684,44 @@ typedef struct pm_call_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** CallOperatorWriteNode#receiver */ + /** + * CallOperatorWriteNode#receiver + */ struct pm_node *receiver; - /** CallOperatorWriteNode#call_operator_loc */ + /** + * CallOperatorWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** CallOperatorWriteNode#message_loc */ + /** + * CallOperatorWriteNode#message_loc + */ pm_location_t message_loc; - /** CallOperatorWriteNode#read_name */ + /** + * CallOperatorWriteNode#read_name + */ pm_constant_id_t read_name; - /** CallOperatorWriteNode#write_name */ + /** + * CallOperatorWriteNode#write_name + */ pm_constant_id_t write_name; - /** CallOperatorWriteNode#operator */ + /** + * CallOperatorWriteNode#operator + */ pm_constant_id_t operator; - /** CallOperatorWriteNode#operator_loc */ + /** + * CallOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** CallOperatorWriteNode#value */ + /** + * CallOperatorWriteNode#value + */ struct pm_node *value; } pm_call_operator_write_node_t; @@ -1549,6 +1732,8 @@ typedef struct pm_call_operator_write_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1556,28 +1741,79 @@ typedef struct pm_call_or_write_node { /** The embedded base node. */ pm_node_t base; - /** CallOrWriteNode#receiver */ + /** + * CallOrWriteNode#receiver + */ struct pm_node *receiver; - /** CallOrWriteNode#call_operator_loc */ + /** + * CallOrWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** CallOrWriteNode#message_loc */ + /** + * CallOrWriteNode#message_loc + */ pm_location_t message_loc; - /** CallOrWriteNode#read_name */ + /** + * CallOrWriteNode#read_name + */ pm_constant_id_t read_name; - /** CallOrWriteNode#write_name */ + /** + * CallOrWriteNode#write_name + */ pm_constant_id_t write_name; - /** CallOrWriteNode#operator_loc */ + /** + * CallOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** CallOrWriteNode#value */ + /** + * CallOrWriteNode#value + */ struct pm_node *value; } pm_call_or_write_node_t; +/** + * CallTargetNode + * + * Type: PM_CALL_TARGET_NODE + * Flags: + * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_call_target_node { + /** The embedded base node. */ + pm_node_t base; + + /** + * CallTargetNode#receiver + */ + struct pm_node *receiver; + + /** + * CallTargetNode#call_operator_loc + */ + pm_location_t call_operator_loc; + + /** + * CallTargetNode#name + */ + pm_constant_id_t name; + + /** + * CallTargetNode#message_loc + */ + pm_location_t message_loc; +} pm_call_target_node_t; + /** * CapturePatternNode * @@ -1589,13 +1825,19 @@ typedef struct pm_capture_pattern_node { /** The embedded base node. */ pm_node_t base; - /** CapturePatternNode#value */ + /** + * CapturePatternNode#value + */ struct pm_node *value; - /** CapturePatternNode#target */ + /** + * CapturePatternNode#target + */ struct pm_node *target; - /** CapturePatternNode#operator_loc */ + /** + * CapturePatternNode#operator_loc + */ pm_location_t operator_loc; } pm_capture_pattern_node_t; @@ -1610,19 +1852,29 @@ typedef struct pm_case_match_node { /** The embedded base node. */ pm_node_t base; - /** CaseMatchNode#predicate */ + /** + * CaseMatchNode#predicate + */ struct pm_node *predicate; - /** CaseMatchNode#conditions */ + /** + * CaseMatchNode#conditions + */ struct pm_node_list conditions; - /** CaseMatchNode#consequent */ + /** + * CaseMatchNode#consequent + */ struct pm_else_node *consequent; - /** CaseMatchNode#case_keyword_loc */ + /** + * CaseMatchNode#case_keyword_loc + */ pm_location_t case_keyword_loc; - /** CaseMatchNode#end_keyword_loc */ + /** + * CaseMatchNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_case_match_node_t; @@ -1637,19 +1889,29 @@ typedef struct pm_case_node { /** The embedded base node. */ pm_node_t base; - /** CaseNode#predicate */ + /** + * CaseNode#predicate + */ struct pm_node *predicate; - /** CaseNode#conditions */ + /** + * CaseNode#conditions + */ struct pm_node_list conditions; - /** CaseNode#consequent */ + /** + * CaseNode#consequent + */ struct pm_else_node *consequent; - /** CaseNode#case_keyword_loc */ + /** + * CaseNode#case_keyword_loc + */ pm_location_t case_keyword_loc; - /** CaseNode#end_keyword_loc */ + /** + * CaseNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_case_node_t; @@ -1664,28 +1926,44 @@ typedef struct pm_class_node { /** The embedded base node. */ pm_node_t base; - /** ClassNode#locals */ + /** + * ClassNode#locals + */ pm_constant_id_list_t locals; - /** ClassNode#class_keyword_loc */ + /** + * ClassNode#class_keyword_loc + */ pm_location_t class_keyword_loc; - /** ClassNode#constant_path */ + /** + * ClassNode#constant_path + */ struct pm_node *constant_path; - /** ClassNode#inheritance_operator_loc */ + /** + * ClassNode#inheritance_operator_loc + */ pm_location_t inheritance_operator_loc; - /** ClassNode#superclass */ + /** + * ClassNode#superclass + */ struct pm_node *superclass; - /** ClassNode#body */ + /** + * ClassNode#body + */ struct pm_node *body; - /** ClassNode#end_keyword_loc */ + /** + * ClassNode#end_keyword_loc + */ pm_location_t end_keyword_loc; - /** ClassNode#name */ + /** + * ClassNode#name + */ pm_constant_id_t name; } pm_class_node_t; @@ -1700,16 +1978,24 @@ typedef struct pm_class_variable_and_write_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableAndWriteNode#name */ + /** + * ClassVariableAndWriteNode#name + */ pm_constant_id_t name; - /** ClassVariableAndWriteNode#name_loc */ + /** + * ClassVariableAndWriteNode#name_loc + */ pm_location_t name_loc; - /** ClassVariableAndWriteNode#operator_loc */ + /** + * ClassVariableAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ClassVariableAndWriteNode#value */ + /** + * ClassVariableAndWriteNode#value + */ struct pm_node *value; } pm_class_variable_and_write_node_t; @@ -1724,20 +2010,30 @@ typedef struct pm_class_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableOperatorWriteNode#name */ + /** + * ClassVariableOperatorWriteNode#name + */ pm_constant_id_t name; - /** ClassVariableOperatorWriteNode#name_loc */ + /** + * ClassVariableOperatorWriteNode#name_loc + */ pm_location_t name_loc; - /** ClassVariableOperatorWriteNode#operator_loc */ + /** + * ClassVariableOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ClassVariableOperatorWriteNode#value */ + /** + * ClassVariableOperatorWriteNode#value + */ struct pm_node *value; - /** ClassVariableOperatorWriteNode#operator */ - pm_constant_id_t operator; + /** + * ClassVariableOperatorWriteNode#operator + */ + pm_constant_id_t operator; } pm_class_variable_operator_write_node_t; /** @@ -1751,16 +2047,24 @@ typedef struct pm_class_variable_or_write_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableOrWriteNode#name */ + /** + * ClassVariableOrWriteNode#name + */ pm_constant_id_t name; - /** ClassVariableOrWriteNode#name_loc */ + /** + * ClassVariableOrWriteNode#name_loc + */ pm_location_t name_loc; - /** ClassVariableOrWriteNode#operator_loc */ + /** + * ClassVariableOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ClassVariableOrWriteNode#value */ + /** + * ClassVariableOrWriteNode#value + */ struct pm_node *value; } pm_class_variable_or_write_node_t; @@ -1775,7 +2079,9 @@ typedef struct pm_class_variable_read_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableReadNode#name */ + /** + * ClassVariableReadNode#name + */ pm_constant_id_t name; } pm_class_variable_read_node_t; @@ -1790,7 +2096,9 @@ typedef struct pm_class_variable_target_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableTargetNode#name */ + /** + * ClassVariableTargetNode#name + */ pm_constant_id_t name; } pm_class_variable_target_node_t; @@ -1805,16 +2113,24 @@ typedef struct pm_class_variable_write_node { /** The embedded base node. */ pm_node_t base; - /** ClassVariableWriteNode#name */ + /** + * ClassVariableWriteNode#name + */ pm_constant_id_t name; - /** ClassVariableWriteNode#name_loc */ + /** + * ClassVariableWriteNode#name_loc + */ pm_location_t name_loc; - /** ClassVariableWriteNode#value */ + /** + * ClassVariableWriteNode#value + */ struct pm_node *value; - /** ClassVariableWriteNode#operator_loc */ + /** + * ClassVariableWriteNode#operator_loc + */ pm_location_t operator_loc; } pm_class_variable_write_node_t; @@ -1829,16 +2145,24 @@ typedef struct pm_constant_and_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantAndWriteNode#name */ + /** + * ConstantAndWriteNode#name + */ pm_constant_id_t name; - /** ConstantAndWriteNode#name_loc */ + /** + * ConstantAndWriteNode#name_loc + */ pm_location_t name_loc; - /** ConstantAndWriteNode#operator_loc */ + /** + * ConstantAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantAndWriteNode#value */ + /** + * ConstantAndWriteNode#value + */ struct pm_node *value; } pm_constant_and_write_node_t; @@ -1853,19 +2177,29 @@ typedef struct pm_constant_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantOperatorWriteNode#name */ + /** + * ConstantOperatorWriteNode#name + */ pm_constant_id_t name; - /** ConstantOperatorWriteNode#name_loc */ + /** + * ConstantOperatorWriteNode#name_loc + */ pm_location_t name_loc; - /** ConstantOperatorWriteNode#operator_loc */ + /** + * ConstantOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantOperatorWriteNode#value */ + /** + * ConstantOperatorWriteNode#value + */ struct pm_node *value; - /** ConstantOperatorWriteNode#operator */ + /** + * ConstantOperatorWriteNode#operator + */ pm_constant_id_t operator; } pm_constant_operator_write_node_t; @@ -1880,16 +2214,24 @@ typedef struct pm_constant_or_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantOrWriteNode#name */ + /** + * ConstantOrWriteNode#name + */ pm_constant_id_t name; - /** ConstantOrWriteNode#name_loc */ + /** + * ConstantOrWriteNode#name_loc + */ pm_location_t name_loc; - /** ConstantOrWriteNode#operator_loc */ + /** + * ConstantOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantOrWriteNode#value */ + /** + * ConstantOrWriteNode#value + */ struct pm_node *value; } pm_constant_or_write_node_t; @@ -1904,13 +2246,19 @@ typedef struct pm_constant_path_and_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathAndWriteNode#target */ + /** + * ConstantPathAndWriteNode#target + */ struct pm_constant_path_node *target; - /** ConstantPathAndWriteNode#operator_loc */ + /** + * ConstantPathAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantPathAndWriteNode#value */ + /** + * ConstantPathAndWriteNode#value + */ struct pm_node *value; } pm_constant_path_and_write_node_t; @@ -1925,13 +2273,19 @@ typedef struct pm_constant_path_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathNode#parent */ + /** + * ConstantPathNode#parent + */ struct pm_node *parent; - /** ConstantPathNode#child */ + /** + * ConstantPathNode#child + */ struct pm_node *child; - /** ConstantPathNode#delimiter_loc */ + /** + * ConstantPathNode#delimiter_loc + */ pm_location_t delimiter_loc; } pm_constant_path_node_t; @@ -1946,16 +2300,24 @@ typedef struct pm_constant_path_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathOperatorWriteNode#target */ + /** + * ConstantPathOperatorWriteNode#target + */ struct pm_constant_path_node *target; - /** ConstantPathOperatorWriteNode#operator_loc */ + /** + * ConstantPathOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantPathOperatorWriteNode#value */ + /** + * ConstantPathOperatorWriteNode#value + */ struct pm_node *value; - /** ConstantPathOperatorWriteNode#operator */ + /** + * ConstantPathOperatorWriteNode#operator + */ pm_constant_id_t operator; } pm_constant_path_operator_write_node_t; @@ -1970,13 +2332,19 @@ typedef struct pm_constant_path_or_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathOrWriteNode#target */ + /** + * ConstantPathOrWriteNode#target + */ struct pm_constant_path_node *target; - /** ConstantPathOrWriteNode#operator_loc */ + /** + * ConstantPathOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantPathOrWriteNode#value */ + /** + * ConstantPathOrWriteNode#value + */ struct pm_node *value; } pm_constant_path_or_write_node_t; @@ -1991,13 +2359,19 @@ typedef struct pm_constant_path_target_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathTargetNode#parent */ + /** + * ConstantPathTargetNode#parent + */ struct pm_node *parent; - /** ConstantPathTargetNode#child */ + /** + * ConstantPathTargetNode#child + */ struct pm_node *child; - /** ConstantPathTargetNode#delimiter_loc */ + /** + * ConstantPathTargetNode#delimiter_loc + */ pm_location_t delimiter_loc; } pm_constant_path_target_node_t; @@ -2012,13 +2386,19 @@ typedef struct pm_constant_path_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantPathWriteNode#target */ + /** + * ConstantPathWriteNode#target + */ struct pm_constant_path_node *target; - /** ConstantPathWriteNode#operator_loc */ + /** + * ConstantPathWriteNode#operator_loc + */ pm_location_t operator_loc; - /** ConstantPathWriteNode#value */ + /** + * ConstantPathWriteNode#value + */ struct pm_node *value; } pm_constant_path_write_node_t; @@ -2033,7 +2413,9 @@ typedef struct pm_constant_read_node { /** The embedded base node. */ pm_node_t base; - /** ConstantReadNode#name */ + /** + * ConstantReadNode#name + */ pm_constant_id_t name; } pm_constant_read_node_t; @@ -2048,7 +2430,9 @@ typedef struct pm_constant_target_node { /** The embedded base node. */ pm_node_t base; - /** ConstantTargetNode#name */ + /** + * ConstantTargetNode#name + */ pm_constant_id_t name; } pm_constant_target_node_t; @@ -2063,16 +2447,24 @@ typedef struct pm_constant_write_node { /** The embedded base node. */ pm_node_t base; - /** ConstantWriteNode#name */ + /** + * ConstantWriteNode#name + */ pm_constant_id_t name; - /** ConstantWriteNode#name_loc */ + /** + * ConstantWriteNode#name_loc + */ pm_location_t name_loc; - /** ConstantWriteNode#value */ + /** + * ConstantWriteNode#value + */ struct pm_node *value; - /** ConstantWriteNode#operator_loc */ + /** + * ConstantWriteNode#operator_loc + */ pm_location_t operator_loc; } pm_constant_write_node_t; @@ -2087,40 +2479,69 @@ typedef struct pm_def_node { /** The embedded base node. */ pm_node_t base; - /** DefNode#name */ + /** + * DefNode#name + */ pm_constant_id_t name; - /** DefNode#name_loc */ + /** + * DefNode#name_loc + */ pm_location_t name_loc; - /** DefNode#receiver */ + /** + * DefNode#receiver + */ struct pm_node *receiver; - /** DefNode#parameters */ + /** + * DefNode#parameters + */ struct pm_parameters_node *parameters; - /** DefNode#body */ + /** + * DefNode#body + */ struct pm_node *body; - /** DefNode#locals */ + /** + * DefNode#locals + */ pm_constant_id_list_t locals; - /** DefNode#def_keyword_loc */ + /** + * DefNode#locals_body_index + */ + uint32_t locals_body_index; + + /** + * DefNode#def_keyword_loc + */ pm_location_t def_keyword_loc; - /** DefNode#operator_loc */ + /** + * DefNode#operator_loc + */ pm_location_t operator_loc; - /** DefNode#lparen_loc */ + /** + * DefNode#lparen_loc + */ pm_location_t lparen_loc; - /** DefNode#rparen_loc */ + /** + * DefNode#rparen_loc + */ pm_location_t rparen_loc; - /** DefNode#equal_loc */ + /** + * DefNode#equal_loc + */ pm_location_t equal_loc; - /** DefNode#end_keyword_loc */ + /** + * DefNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_def_node_t; @@ -2135,16 +2556,24 @@ typedef struct pm_defined_node { /** The embedded base node. */ pm_node_t base; - /** DefinedNode#lparen_loc */ + /** + * DefinedNode#lparen_loc + */ pm_location_t lparen_loc; - /** DefinedNode#value */ + /** + * DefinedNode#value + */ struct pm_node *value; - /** DefinedNode#rparen_loc */ + /** + * DefinedNode#rparen_loc + */ pm_location_t rparen_loc; - /** DefinedNode#keyword_loc */ + /** + * DefinedNode#keyword_loc + */ pm_location_t keyword_loc; } pm_defined_node_t; @@ -2159,13 +2588,19 @@ typedef struct pm_else_node { /** The embedded base node. */ pm_node_t base; - /** ElseNode#else_keyword_loc */ + /** + * ElseNode#else_keyword_loc + */ pm_location_t else_keyword_loc; - /** ElseNode#statements */ + /** + * ElseNode#statements + */ struct pm_statements_node *statements; - /** ElseNode#end_keyword_loc */ + /** + * ElseNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_else_node_t; @@ -2180,13 +2615,19 @@ typedef struct pm_embedded_statements_node { /** The embedded base node. */ pm_node_t base; - /** EmbeddedStatementsNode#opening_loc */ + /** + * EmbeddedStatementsNode#opening_loc + */ pm_location_t opening_loc; - /** EmbeddedStatementsNode#statements */ + /** + * EmbeddedStatementsNode#statements + */ struct pm_statements_node *statements; - /** EmbeddedStatementsNode#closing_loc */ + /** + * EmbeddedStatementsNode#closing_loc + */ pm_location_t closing_loc; } pm_embedded_statements_node_t; @@ -2201,10 +2642,14 @@ typedef struct pm_embedded_variable_node { /** The embedded base node. */ pm_node_t base; - /** EmbeddedVariableNode#operator_loc */ + /** + * EmbeddedVariableNode#operator_loc + */ pm_location_t operator_loc; - /** EmbeddedVariableNode#variable */ + /** + * EmbeddedVariableNode#variable + */ struct pm_node *variable; } pm_embedded_variable_node_t; @@ -2219,13 +2664,19 @@ typedef struct pm_ensure_node { /** The embedded base node. */ pm_node_t base; - /** EnsureNode#ensure_keyword_loc */ + /** + * EnsureNode#ensure_keyword_loc + */ pm_location_t ensure_keyword_loc; - /** EnsureNode#statements */ + /** + * EnsureNode#statements + */ struct pm_statements_node *statements; - /** EnsureNode#end_keyword_loc */ + /** + * EnsureNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_ensure_node_t; @@ -2252,22 +2703,34 @@ typedef struct pm_find_pattern_node { /** The embedded base node. */ pm_node_t base; - /** FindPatternNode#constant */ + /** + * FindPatternNode#constant + */ struct pm_node *constant; - /** FindPatternNode#left */ + /** + * FindPatternNode#left + */ struct pm_node *left; - /** FindPatternNode#requireds */ + /** + * FindPatternNode#requireds + */ struct pm_node_list requireds; - /** FindPatternNode#right */ + /** + * FindPatternNode#right + */ struct pm_node *right; - /** FindPatternNode#opening_loc */ + /** + * FindPatternNode#opening_loc + */ pm_location_t opening_loc; - /** FindPatternNode#closing_loc */ + /** + * FindPatternNode#closing_loc + */ pm_location_t closing_loc; } pm_find_pattern_node_t; @@ -2284,13 +2747,19 @@ typedef struct pm_flip_flop_node { /** The embedded base node. */ pm_node_t base; - /** FlipFlopNode#left */ + /** + * FlipFlopNode#left + */ struct pm_node *left; - /** FlipFlopNode#right */ + /** + * FlipFlopNode#right + */ struct pm_node *right; - /** FlipFlopNode#operator_loc */ + /** + * FlipFlopNode#operator_loc + */ pm_location_t operator_loc; } pm_flip_flop_node_t; @@ -2317,25 +2786,39 @@ typedef struct pm_for_node { /** The embedded base node. */ pm_node_t base; - /** ForNode#index */ + /** + * ForNode#index + */ struct pm_node *index; - /** ForNode#collection */ + /** + * ForNode#collection + */ struct pm_node *collection; - /** ForNode#statements */ + /** + * ForNode#statements + */ struct pm_statements_node *statements; - /** ForNode#for_keyword_loc */ + /** + * ForNode#for_keyword_loc + */ pm_location_t for_keyword_loc; - /** ForNode#in_keyword_loc */ + /** + * ForNode#in_keyword_loc + */ pm_location_t in_keyword_loc; - /** ForNode#do_keyword_loc */ + /** + * ForNode#do_keyword_loc + */ pm_location_t do_keyword_loc; - /** ForNode#end_keyword_loc */ + /** + * ForNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_for_node_t; @@ -2374,7 +2857,9 @@ typedef struct pm_forwarding_super_node { /** The embedded base node. */ pm_node_t base; - /** ForwardingSuperNode#block */ + /** + * ForwardingSuperNode#block + */ struct pm_block_node *block; } pm_forwarding_super_node_t; @@ -2389,16 +2874,24 @@ typedef struct pm_global_variable_and_write_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableAndWriteNode#name */ + /** + * GlobalVariableAndWriteNode#name + */ pm_constant_id_t name; - /** GlobalVariableAndWriteNode#name_loc */ + /** + * GlobalVariableAndWriteNode#name_loc + */ pm_location_t name_loc; - /** GlobalVariableAndWriteNode#operator_loc */ + /** + * GlobalVariableAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** GlobalVariableAndWriteNode#value */ + /** + * GlobalVariableAndWriteNode#value + */ struct pm_node *value; } pm_global_variable_and_write_node_t; @@ -2413,19 +2906,29 @@ typedef struct pm_global_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableOperatorWriteNode#name */ + /** + * GlobalVariableOperatorWriteNode#name + */ pm_constant_id_t name; - /** GlobalVariableOperatorWriteNode#name_loc */ + /** + * GlobalVariableOperatorWriteNode#name_loc + */ pm_location_t name_loc; - /** GlobalVariableOperatorWriteNode#operator_loc */ + /** + * GlobalVariableOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** GlobalVariableOperatorWriteNode#value */ + /** + * GlobalVariableOperatorWriteNode#value + */ struct pm_node *value; - /** GlobalVariableOperatorWriteNode#operator */ + /** + * GlobalVariableOperatorWriteNode#operator + */ pm_constant_id_t operator; } pm_global_variable_operator_write_node_t; @@ -2440,16 +2943,24 @@ typedef struct pm_global_variable_or_write_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableOrWriteNode#name */ + /** + * GlobalVariableOrWriteNode#name + */ pm_constant_id_t name; - /** GlobalVariableOrWriteNode#name_loc */ + /** + * GlobalVariableOrWriteNode#name_loc + */ pm_location_t name_loc; - /** GlobalVariableOrWriteNode#operator_loc */ + /** + * GlobalVariableOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** GlobalVariableOrWriteNode#value */ + /** + * GlobalVariableOrWriteNode#value + */ struct pm_node *value; } pm_global_variable_or_write_node_t; @@ -2464,7 +2975,9 @@ typedef struct pm_global_variable_read_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableReadNode#name */ + /** + * GlobalVariableReadNode#name + */ pm_constant_id_t name; } pm_global_variable_read_node_t; @@ -2479,7 +2992,9 @@ typedef struct pm_global_variable_target_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableTargetNode#name */ + /** + * GlobalVariableTargetNode#name + */ pm_constant_id_t name; } pm_global_variable_target_node_t; @@ -2494,16 +3009,24 @@ typedef struct pm_global_variable_write_node { /** The embedded base node. */ pm_node_t base; - /** GlobalVariableWriteNode#name */ + /** + * GlobalVariableWriteNode#name + */ pm_constant_id_t name; - /** GlobalVariableWriteNode#name_loc */ + /** + * GlobalVariableWriteNode#name_loc + */ pm_location_t name_loc; - /** GlobalVariableWriteNode#value */ + /** + * GlobalVariableWriteNode#value + */ struct pm_node *value; - /** GlobalVariableWriteNode#operator_loc */ + /** + * GlobalVariableWriteNode#operator_loc + */ pm_location_t operator_loc; } pm_global_variable_write_node_t; @@ -2518,13 +3041,19 @@ typedef struct pm_hash_node { /** The embedded base node. */ pm_node_t base; - /** HashNode#opening_loc */ + /** + * HashNode#opening_loc + */ pm_location_t opening_loc; - /** HashNode#elements */ + /** + * HashNode#elements + */ struct pm_node_list elements; - /** HashNode#closing_loc */ + /** + * HashNode#closing_loc + */ pm_location_t closing_loc; } pm_hash_node_t; @@ -2539,19 +3068,29 @@ typedef struct pm_hash_pattern_node { /** The embedded base node. */ pm_node_t base; - /** HashPatternNode#constant */ + /** + * HashPatternNode#constant + */ struct pm_node *constant; - /** HashPatternNode#elements */ + /** + * HashPatternNode#elements + */ struct pm_node_list elements; - /** HashPatternNode#rest */ + /** + * HashPatternNode#rest + */ struct pm_node *rest; - /** HashPatternNode#opening_loc */ + /** + * HashPatternNode#opening_loc + */ pm_location_t opening_loc; - /** HashPatternNode#closing_loc */ + /** + * HashPatternNode#closing_loc + */ pm_location_t closing_loc; } pm_hash_pattern_node_t; @@ -2566,22 +3105,34 @@ typedef struct pm_if_node { /** The embedded base node. */ pm_node_t base; - /** IfNode#if_keyword_loc */ + /** + * IfNode#if_keyword_loc + */ pm_location_t if_keyword_loc; - /** IfNode#predicate */ + /** + * IfNode#predicate + */ struct pm_node *predicate; - /** IfNode#then_keyword_loc */ + /** + * IfNode#then_keyword_loc + */ pm_location_t then_keyword_loc; - /** IfNode#statements */ + /** + * IfNode#statements + */ struct pm_statements_node *statements; - /** IfNode#consequent */ + /** + * IfNode#consequent + */ struct pm_node *consequent; - /** IfNode#end_keyword_loc */ + /** + * IfNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_if_node_t; @@ -2596,7 +3147,9 @@ typedef struct pm_imaginary_node { /** The embedded base node. */ pm_node_t base; - /** ImaginaryNode#numeric */ + /** + * ImaginaryNode#numeric + */ struct pm_node *numeric; } pm_imaginary_node_t; @@ -2611,7 +3164,9 @@ typedef struct pm_implicit_node { /** The embedded base node. */ pm_node_t base; - /** ImplicitNode#value */ + /** + * ImplicitNode#value + */ struct pm_node *value; } pm_implicit_node_t; @@ -2638,16 +3193,24 @@ typedef struct pm_in_node { /** The embedded base node. */ pm_node_t base; - /** InNode#pattern */ + /** + * InNode#pattern + */ struct pm_node *pattern; - /** InNode#statements */ + /** + * InNode#statements + */ struct pm_statements_node *statements; - /** InNode#in_loc */ + /** + * InNode#in_loc + */ pm_location_t in_loc; - /** InNode#then_loc */ + /** + * InNode#then_loc + */ pm_location_t then_loc; } pm_in_node_t; @@ -2658,6 +3221,8 @@ typedef struct pm_in_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -2665,28 +3230,44 @@ typedef struct pm_index_and_write_node { /** The embedded base node. */ pm_node_t base; - /** IndexAndWriteNode#receiver */ + /** + * IndexAndWriteNode#receiver + */ struct pm_node *receiver; - /** IndexAndWriteNode#call_operator_loc */ + /** + * IndexAndWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** IndexAndWriteNode#opening_loc */ + /** + * IndexAndWriteNode#opening_loc + */ pm_location_t opening_loc; - /** IndexAndWriteNode#arguments */ + /** + * IndexAndWriteNode#arguments + */ struct pm_arguments_node *arguments; - /** IndexAndWriteNode#closing_loc */ + /** + * IndexAndWriteNode#closing_loc + */ pm_location_t closing_loc; - /** IndexAndWriteNode#block */ + /** + * IndexAndWriteNode#block + */ struct pm_node *block; - /** IndexAndWriteNode#operator_loc */ + /** + * IndexAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** IndexAndWriteNode#value */ + /** + * IndexAndWriteNode#value + */ struct pm_node *value; } pm_index_and_write_node_t; @@ -2697,6 +3278,8 @@ typedef struct pm_index_and_write_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -2704,31 +3287,49 @@ typedef struct pm_index_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** IndexOperatorWriteNode#receiver */ + /** + * IndexOperatorWriteNode#receiver + */ struct pm_node *receiver; - /** IndexOperatorWriteNode#call_operator_loc */ + /** + * IndexOperatorWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** IndexOperatorWriteNode#opening_loc */ + /** + * IndexOperatorWriteNode#opening_loc + */ pm_location_t opening_loc; - /** IndexOperatorWriteNode#arguments */ + /** + * IndexOperatorWriteNode#arguments + */ struct pm_arguments_node *arguments; - /** IndexOperatorWriteNode#closing_loc */ + /** + * IndexOperatorWriteNode#closing_loc + */ pm_location_t closing_loc; - /** IndexOperatorWriteNode#block */ + /** + * IndexOperatorWriteNode#block + */ struct pm_node *block; - /** IndexOperatorWriteNode#operator */ + /** + * IndexOperatorWriteNode#operator + */ pm_constant_id_t operator; - /** IndexOperatorWriteNode#operator_loc */ + /** + * IndexOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** IndexOperatorWriteNode#value */ + /** + * IndexOperatorWriteNode#value + */ struct pm_node *value; } pm_index_operator_write_node_t; @@ -2739,6 +3340,8 @@ typedef struct pm_index_operator_write_node { * Flags: * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -2746,31 +3349,89 @@ typedef struct pm_index_or_write_node { /** The embedded base node. */ pm_node_t base; - /** IndexOrWriteNode#receiver */ + /** + * IndexOrWriteNode#receiver + */ struct pm_node *receiver; - /** IndexOrWriteNode#call_operator_loc */ + /** + * IndexOrWriteNode#call_operator_loc + */ pm_location_t call_operator_loc; - /** IndexOrWriteNode#opening_loc */ + /** + * IndexOrWriteNode#opening_loc + */ pm_location_t opening_loc; - /** IndexOrWriteNode#arguments */ + /** + * IndexOrWriteNode#arguments + */ struct pm_arguments_node *arguments; - /** IndexOrWriteNode#closing_loc */ + /** + * IndexOrWriteNode#closing_loc + */ pm_location_t closing_loc; - /** IndexOrWriteNode#block */ + /** + * IndexOrWriteNode#block + */ struct pm_node *block; - /** IndexOrWriteNode#operator_loc */ + /** + * IndexOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** IndexOrWriteNode#value */ + /** + * IndexOrWriteNode#value + */ struct pm_node *value; } pm_index_or_write_node_t; +/** + * IndexTargetNode + * + * Type: PM_INDEX_TARGET_NODE + * Flags: + * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * PM_CALL_NODE_FLAGS_VARIABLE_CALL + * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * + * @extends pm_node_t + */ +typedef struct pm_index_target_node { + /** The embedded base node. */ + pm_node_t base; + + /** + * IndexTargetNode#receiver + */ + struct pm_node *receiver; + + /** + * IndexTargetNode#opening_loc + */ + pm_location_t opening_loc; + + /** + * IndexTargetNode#arguments + */ + struct pm_arguments_node *arguments; + + /** + * IndexTargetNode#closing_loc + */ + pm_location_t closing_loc; + + /** + * IndexTargetNode#block + */ + struct pm_node *block; +} pm_index_target_node_t; + /** * InstanceVariableAndWriteNode * @@ -2782,16 +3443,24 @@ typedef struct pm_instance_variable_and_write_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableAndWriteNode#name */ + /** + * InstanceVariableAndWriteNode#name + */ pm_constant_id_t name; - /** InstanceVariableAndWriteNode#name_loc */ + /** + * InstanceVariableAndWriteNode#name_loc + */ pm_location_t name_loc; - /** InstanceVariableAndWriteNode#operator_loc */ + /** + * InstanceVariableAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** InstanceVariableAndWriteNode#value */ + /** + * InstanceVariableAndWriteNode#value + */ struct pm_node *value; } pm_instance_variable_and_write_node_t; @@ -2806,19 +3475,29 @@ typedef struct pm_instance_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableOperatorWriteNode#name */ + /** + * InstanceVariableOperatorWriteNode#name + */ pm_constant_id_t name; - /** InstanceVariableOperatorWriteNode#name_loc */ + /** + * InstanceVariableOperatorWriteNode#name_loc + */ pm_location_t name_loc; - /** InstanceVariableOperatorWriteNode#operator_loc */ + /** + * InstanceVariableOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** InstanceVariableOperatorWriteNode#value */ + /** + * InstanceVariableOperatorWriteNode#value + */ struct pm_node *value; - /** InstanceVariableOperatorWriteNode#operator */ + /** + * InstanceVariableOperatorWriteNode#operator + */ pm_constant_id_t operator; } pm_instance_variable_operator_write_node_t; @@ -2833,16 +3512,24 @@ typedef struct pm_instance_variable_or_write_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableOrWriteNode#name */ + /** + * InstanceVariableOrWriteNode#name + */ pm_constant_id_t name; - /** InstanceVariableOrWriteNode#name_loc */ + /** + * InstanceVariableOrWriteNode#name_loc + */ pm_location_t name_loc; - /** InstanceVariableOrWriteNode#operator_loc */ + /** + * InstanceVariableOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** InstanceVariableOrWriteNode#value */ + /** + * InstanceVariableOrWriteNode#value + */ struct pm_node *value; } pm_instance_variable_or_write_node_t; @@ -2857,7 +3544,9 @@ typedef struct pm_instance_variable_read_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableReadNode#name */ + /** + * InstanceVariableReadNode#name + */ pm_constant_id_t name; } pm_instance_variable_read_node_t; @@ -2872,7 +3561,9 @@ typedef struct pm_instance_variable_target_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableTargetNode#name */ + /** + * InstanceVariableTargetNode#name + */ pm_constant_id_t name; } pm_instance_variable_target_node_t; @@ -2887,16 +3578,24 @@ typedef struct pm_instance_variable_write_node { /** The embedded base node. */ pm_node_t base; - /** InstanceVariableWriteNode#name */ + /** + * InstanceVariableWriteNode#name + */ pm_constant_id_t name; - /** InstanceVariableWriteNode#name_loc */ + /** + * InstanceVariableWriteNode#name_loc + */ pm_location_t name_loc; - /** InstanceVariableWriteNode#value */ + /** + * InstanceVariableWriteNode#value + */ struct pm_node *value; - /** InstanceVariableWriteNode#operator_loc */ + /** + * InstanceVariableWriteNode#operator_loc + */ pm_location_t operator_loc; } pm_instance_variable_write_node_t; @@ -2906,8 +3605,8 @@ typedef struct pm_instance_variable_write_node { * Type: PM_INTEGER_NODE * Flags: * PM_INTEGER_BASE_FLAGS_BINARY - * PM_INTEGER_BASE_FLAGS_OCTAL * PM_INTEGER_BASE_FLAGS_DECIMAL + * PM_INTEGER_BASE_FLAGS_OCTAL * PM_INTEGER_BASE_FLAGS_HEXADECIMAL * * @extends pm_node_t @@ -2930,6 +3629,9 @@ typedef struct pm_integer_node { * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -2937,13 +3639,19 @@ typedef struct pm_interpolated_match_last_line_node { /** The embedded base node. */ pm_node_t base; - /** InterpolatedMatchLastLineNode#opening_loc */ + /** + * InterpolatedMatchLastLineNode#opening_loc + */ pm_location_t opening_loc; - /** InterpolatedMatchLastLineNode#parts */ + /** + * InterpolatedMatchLastLineNode#parts + */ struct pm_node_list parts; - /** InterpolatedMatchLastLineNode#closing_loc */ + /** + * InterpolatedMatchLastLineNode#closing_loc + */ pm_location_t closing_loc; } pm_interpolated_match_last_line_node_t; @@ -2960,6 +3668,9 @@ typedef struct pm_interpolated_match_last_line_node { * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -2967,13 +3678,19 @@ typedef struct pm_interpolated_regular_expression_node { /** The embedded base node. */ pm_node_t base; - /** InterpolatedRegularExpressionNode#opening_loc */ + /** + * InterpolatedRegularExpressionNode#opening_loc + */ pm_location_t opening_loc; - /** InterpolatedRegularExpressionNode#parts */ + /** + * InterpolatedRegularExpressionNode#parts + */ struct pm_node_list parts; - /** InterpolatedRegularExpressionNode#closing_loc */ + /** + * InterpolatedRegularExpressionNode#closing_loc + */ pm_location_t closing_loc; } pm_interpolated_regular_expression_node_t; @@ -2988,13 +3705,19 @@ typedef struct pm_interpolated_string_node { /** The embedded base node. */ pm_node_t base; - /** InterpolatedStringNode#opening_loc */ + /** + * InterpolatedStringNode#opening_loc + */ pm_location_t opening_loc; - /** InterpolatedStringNode#parts */ + /** + * InterpolatedStringNode#parts + */ struct pm_node_list parts; - /** InterpolatedStringNode#closing_loc */ + /** + * InterpolatedStringNode#closing_loc + */ pm_location_t closing_loc; } pm_interpolated_string_node_t; @@ -3009,13 +3732,19 @@ typedef struct pm_interpolated_symbol_node { /** The embedded base node. */ pm_node_t base; - /** InterpolatedSymbolNode#opening_loc */ + /** + * InterpolatedSymbolNode#opening_loc + */ pm_location_t opening_loc; - /** InterpolatedSymbolNode#parts */ + /** + * InterpolatedSymbolNode#parts + */ struct pm_node_list parts; - /** InterpolatedSymbolNode#closing_loc */ + /** + * InterpolatedSymbolNode#closing_loc + */ pm_location_t closing_loc; } pm_interpolated_symbol_node_t; @@ -3030,13 +3759,19 @@ typedef struct pm_interpolated_x_string_node { /** The embedded base node. */ pm_node_t base; - /** InterpolatedXStringNode#opening_loc */ + /** + * InterpolatedXStringNode#opening_loc + */ pm_location_t opening_loc; - /** InterpolatedXStringNode#parts */ + /** + * InterpolatedXStringNode#parts + */ struct pm_node_list parts; - /** InterpolatedXStringNode#closing_loc */ + /** + * InterpolatedXStringNode#closing_loc + */ pm_location_t closing_loc; } pm_interpolated_x_string_node_t; @@ -3044,6 +3779,8 @@ typedef struct pm_interpolated_x_string_node { * KeywordHashNode * * Type: PM_KEYWORD_HASH_NODE + * Flags: + * PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS * * @extends pm_node_t */ @@ -3051,7 +3788,9 @@ typedef struct pm_keyword_hash_node { /** The embedded base node. */ pm_node_t base; - /** KeywordHashNode#elements */ + /** + * KeywordHashNode#elements + */ struct pm_node_list elements; } pm_keyword_hash_node_t; @@ -3066,13 +3805,19 @@ typedef struct pm_keyword_rest_parameter_node { /** The embedded base node. */ pm_node_t base; - /** KeywordRestParameterNode#name */ + /** + * KeywordRestParameterNode#name + */ pm_constant_id_t name; - /** KeywordRestParameterNode#name_loc */ + /** + * KeywordRestParameterNode#name_loc + */ pm_location_t name_loc; - /** KeywordRestParameterNode#operator_loc */ + /** + * KeywordRestParameterNode#operator_loc + */ pm_location_t operator_loc; } pm_keyword_rest_parameter_node_t; @@ -3087,22 +3832,39 @@ typedef struct pm_lambda_node { /** The embedded base node. */ pm_node_t base; - /** LambdaNode#locals */ + /** + * LambdaNode#locals + */ pm_constant_id_list_t locals; - /** LambdaNode#operator_loc */ + /** + * LambdaNode#locals_body_index + */ + uint32_t locals_body_index; + + /** + * LambdaNode#operator_loc + */ pm_location_t operator_loc; - /** LambdaNode#opening_loc */ + /** + * LambdaNode#opening_loc + */ pm_location_t opening_loc; - /** LambdaNode#closing_loc */ + /** + * LambdaNode#closing_loc + */ pm_location_t closing_loc; - /** LambdaNode#parameters */ + /** + * LambdaNode#parameters + */ struct pm_node *parameters; - /** LambdaNode#body */ + /** + * LambdaNode#body + */ struct pm_node *body; } pm_lambda_node_t; @@ -3117,19 +3879,29 @@ typedef struct pm_local_variable_and_write_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableAndWriteNode#name_loc */ + /** + * LocalVariableAndWriteNode#name_loc + */ pm_location_t name_loc; - /** LocalVariableAndWriteNode#operator_loc */ + /** + * LocalVariableAndWriteNode#operator_loc + */ pm_location_t operator_loc; - /** LocalVariableAndWriteNode#value */ + /** + * LocalVariableAndWriteNode#value + */ struct pm_node *value; - /** LocalVariableAndWriteNode#name */ + /** + * LocalVariableAndWriteNode#name + */ pm_constant_id_t name; - /** LocalVariableAndWriteNode#depth */ + /** + * LocalVariableAndWriteNode#depth + */ uint32_t depth; } pm_local_variable_and_write_node_t; @@ -3144,22 +3916,34 @@ typedef struct pm_local_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableOperatorWriteNode#name_loc */ + /** + * LocalVariableOperatorWriteNode#name_loc + */ pm_location_t name_loc; - /** LocalVariableOperatorWriteNode#operator_loc */ + /** + * LocalVariableOperatorWriteNode#operator_loc + */ pm_location_t operator_loc; - /** LocalVariableOperatorWriteNode#value */ + /** + * LocalVariableOperatorWriteNode#value + */ struct pm_node *value; - /** LocalVariableOperatorWriteNode#name */ + /** + * LocalVariableOperatorWriteNode#name + */ pm_constant_id_t name; - /** LocalVariableOperatorWriteNode#operator */ + /** + * LocalVariableOperatorWriteNode#operator + */ pm_constant_id_t operator; - /** LocalVariableOperatorWriteNode#depth */ + /** + * LocalVariableOperatorWriteNode#depth + */ uint32_t depth; } pm_local_variable_operator_write_node_t; @@ -3174,19 +3958,29 @@ typedef struct pm_local_variable_or_write_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableOrWriteNode#name_loc */ + /** + * LocalVariableOrWriteNode#name_loc + */ pm_location_t name_loc; - /** LocalVariableOrWriteNode#operator_loc */ + /** + * LocalVariableOrWriteNode#operator_loc + */ pm_location_t operator_loc; - /** LocalVariableOrWriteNode#value */ + /** + * LocalVariableOrWriteNode#value + */ struct pm_node *value; - /** LocalVariableOrWriteNode#name */ + /** + * LocalVariableOrWriteNode#name + */ pm_constant_id_t name; - /** LocalVariableOrWriteNode#depth */ + /** + * LocalVariableOrWriteNode#depth + */ uint32_t depth; } pm_local_variable_or_write_node_t; @@ -3201,10 +3995,14 @@ typedef struct pm_local_variable_read_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableReadNode#name */ + /** + * LocalVariableReadNode#name + */ pm_constant_id_t name; - /** LocalVariableReadNode#depth */ + /** + * LocalVariableReadNode#depth + */ uint32_t depth; } pm_local_variable_read_node_t; @@ -3219,10 +4017,14 @@ typedef struct pm_local_variable_target_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableTargetNode#name */ + /** + * LocalVariableTargetNode#name + */ pm_constant_id_t name; - /** LocalVariableTargetNode#depth */ + /** + * LocalVariableTargetNode#depth + */ uint32_t depth; } pm_local_variable_target_node_t; @@ -3237,19 +4039,29 @@ typedef struct pm_local_variable_write_node { /** The embedded base node. */ pm_node_t base; - /** LocalVariableWriteNode#name */ + /** + * LocalVariableWriteNode#name + */ pm_constant_id_t name; - /** LocalVariableWriteNode#depth */ + /** + * LocalVariableWriteNode#depth + */ uint32_t depth; - /** LocalVariableWriteNode#name_loc */ + /** + * LocalVariableWriteNode#name_loc + */ pm_location_t name_loc; - /** LocalVariableWriteNode#value */ + /** + * LocalVariableWriteNode#value + */ struct pm_node *value; - /** LocalVariableWriteNode#operator_loc */ + /** + * LocalVariableWriteNode#operator_loc + */ pm_location_t operator_loc; } pm_local_variable_write_node_t; @@ -3266,6 +4078,9 @@ typedef struct pm_local_variable_write_node { * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -3273,16 +4088,24 @@ typedef struct pm_match_last_line_node { /** The embedded base node. */ pm_node_t base; - /** MatchLastLineNode#opening_loc */ + /** + * MatchLastLineNode#opening_loc + */ pm_location_t opening_loc; - /** MatchLastLineNode#content_loc */ + /** + * MatchLastLineNode#content_loc + */ pm_location_t content_loc; - /** MatchLastLineNode#closing_loc */ + /** + * MatchLastLineNode#closing_loc + */ pm_location_t closing_loc; - /** MatchLastLineNode#unescaped */ + /** + * MatchLastLineNode#unescaped + */ pm_string_t unescaped; } pm_match_last_line_node_t; @@ -3297,13 +4120,19 @@ typedef struct pm_match_predicate_node { /** The embedded base node. */ pm_node_t base; - /** MatchPredicateNode#value */ + /** + * MatchPredicateNode#value + */ struct pm_node *value; - /** MatchPredicateNode#pattern */ + /** + * MatchPredicateNode#pattern + */ struct pm_node *pattern; - /** MatchPredicateNode#operator_loc */ + /** + * MatchPredicateNode#operator_loc + */ pm_location_t operator_loc; } pm_match_predicate_node_t; @@ -3318,13 +4147,19 @@ typedef struct pm_match_required_node { /** The embedded base node. */ pm_node_t base; - /** MatchRequiredNode#value */ + /** + * MatchRequiredNode#value + */ struct pm_node *value; - /** MatchRequiredNode#pattern */ + /** + * MatchRequiredNode#pattern + */ struct pm_node *pattern; - /** MatchRequiredNode#operator_loc */ + /** + * MatchRequiredNode#operator_loc + */ pm_location_t operator_loc; } pm_match_required_node_t; @@ -3339,10 +4174,14 @@ typedef struct pm_match_write_node { /** The embedded base node. */ pm_node_t base; - /** MatchWriteNode#call */ + /** + * MatchWriteNode#call + */ struct pm_call_node *call; - /** MatchWriteNode#targets */ + /** + * MatchWriteNode#targets + */ struct pm_node_list targets; } pm_match_write_node_t; @@ -3369,22 +4208,34 @@ typedef struct pm_module_node { /** The embedded base node. */ pm_node_t base; - /** ModuleNode#locals */ + /** + * ModuleNode#locals + */ pm_constant_id_list_t locals; - /** ModuleNode#module_keyword_loc */ + /** + * ModuleNode#module_keyword_loc + */ pm_location_t module_keyword_loc; - /** ModuleNode#constant_path */ + /** + * ModuleNode#constant_path + */ struct pm_node *constant_path; - /** ModuleNode#body */ + /** + * ModuleNode#body + */ struct pm_node *body; - /** ModuleNode#end_keyword_loc */ + /** + * ModuleNode#end_keyword_loc + */ pm_location_t end_keyword_loc; - /** ModuleNode#name */ + /** + * ModuleNode#name + */ pm_constant_id_t name; } pm_module_node_t; @@ -3399,19 +4250,29 @@ typedef struct pm_multi_target_node { /** The embedded base node. */ pm_node_t base; - /** MultiTargetNode#lefts */ + /** + * MultiTargetNode#lefts + */ struct pm_node_list lefts; - /** MultiTargetNode#rest */ + /** + * MultiTargetNode#rest + */ struct pm_node *rest; - /** MultiTargetNode#rights */ + /** + * MultiTargetNode#rights + */ struct pm_node_list rights; - /** MultiTargetNode#lparen_loc */ + /** + * MultiTargetNode#lparen_loc + */ pm_location_t lparen_loc; - /** MultiTargetNode#rparen_loc */ + /** + * MultiTargetNode#rparen_loc + */ pm_location_t rparen_loc; } pm_multi_target_node_t; @@ -3426,25 +4287,39 @@ typedef struct pm_multi_write_node { /** The embedded base node. */ pm_node_t base; - /** MultiWriteNode#lefts */ + /** + * MultiWriteNode#lefts + */ struct pm_node_list lefts; - /** MultiWriteNode#rest */ + /** + * MultiWriteNode#rest + */ struct pm_node *rest; - /** MultiWriteNode#rights */ + /** + * MultiWriteNode#rights + */ struct pm_node_list rights; - /** MultiWriteNode#lparen_loc */ + /** + * MultiWriteNode#lparen_loc + */ pm_location_t lparen_loc; - /** MultiWriteNode#rparen_loc */ + /** + * MultiWriteNode#rparen_loc + */ pm_location_t rparen_loc; - /** MultiWriteNode#operator_loc */ + /** + * MultiWriteNode#operator_loc + */ pm_location_t operator_loc; - /** MultiWriteNode#value */ + /** + * MultiWriteNode#value + */ struct pm_node *value; } pm_multi_write_node_t; @@ -3459,10 +4334,14 @@ typedef struct pm_next_node { /** The embedded base node. */ pm_node_t base; - /** NextNode#arguments */ + /** + * NextNode#arguments + */ struct pm_arguments_node *arguments; - /** NextNode#keyword_loc */ + /** + * NextNode#keyword_loc + */ pm_location_t keyword_loc; } pm_next_node_t; @@ -3489,10 +4368,14 @@ typedef struct pm_no_keywords_parameter_node { /** The embedded base node. */ pm_node_t base; - /** NoKeywordsParameterNode#operator_loc */ + /** + * NoKeywordsParameterNode#operator_loc + */ pm_location_t operator_loc; - /** NoKeywordsParameterNode#keyword_loc */ + /** + * NoKeywordsParameterNode#keyword_loc + */ pm_location_t keyword_loc; } pm_no_keywords_parameter_node_t; @@ -3507,7 +4390,9 @@ typedef struct pm_numbered_parameters_node { /** The embedded base node. */ pm_node_t base; - /** NumberedParametersNode#maximum */ + /** + * NumberedParametersNode#maximum + */ uint8_t maximum; } pm_numbered_parameters_node_t; @@ -3522,7 +4407,9 @@ typedef struct pm_numbered_reference_read_node { /** The embedded base node. */ pm_node_t base; - /** NumberedReferenceReadNode#number */ + /** + * NumberedReferenceReadNode#number + */ uint32_t number; } pm_numbered_reference_read_node_t; @@ -3537,13 +4424,19 @@ typedef struct pm_optional_keyword_parameter_node { /** The embedded base node. */ pm_node_t base; - /** OptionalKeywordParameterNode#name */ + /** + * OptionalKeywordParameterNode#name + */ pm_constant_id_t name; - /** OptionalKeywordParameterNode#name_loc */ + /** + * OptionalKeywordParameterNode#name_loc + */ pm_location_t name_loc; - /** OptionalKeywordParameterNode#value */ + /** + * OptionalKeywordParameterNode#value + */ struct pm_node *value; } pm_optional_keyword_parameter_node_t; @@ -3558,16 +4451,24 @@ typedef struct pm_optional_parameter_node { /** The embedded base node. */ pm_node_t base; - /** OptionalParameterNode#name */ + /** + * OptionalParameterNode#name + */ pm_constant_id_t name; - /** OptionalParameterNode#name_loc */ + /** + * OptionalParameterNode#name_loc + */ pm_location_t name_loc; - /** OptionalParameterNode#operator_loc */ + /** + * OptionalParameterNode#operator_loc + */ pm_location_t operator_loc; - /** OptionalParameterNode#value */ + /** + * OptionalParameterNode#value + */ struct pm_node *value; } pm_optional_parameter_node_t; @@ -3582,13 +4483,19 @@ typedef struct pm_or_node { /** The embedded base node. */ pm_node_t base; - /** OrNode#left */ + /** + * OrNode#left + */ struct pm_node *left; - /** OrNode#right */ + /** + * OrNode#right + */ struct pm_node *right; - /** OrNode#operator_loc */ + /** + * OrNode#operator_loc + */ pm_location_t operator_loc; } pm_or_node_t; @@ -3603,25 +4510,39 @@ typedef struct pm_parameters_node { /** The embedded base node. */ pm_node_t base; - /** ParametersNode#requireds */ + /** + * ParametersNode#requireds + */ struct pm_node_list requireds; - /** ParametersNode#optionals */ + /** + * ParametersNode#optionals + */ struct pm_node_list optionals; - /** ParametersNode#rest */ + /** + * ParametersNode#rest + */ struct pm_node *rest; - /** ParametersNode#posts */ + /** + * ParametersNode#posts + */ struct pm_node_list posts; - /** ParametersNode#keywords */ + /** + * ParametersNode#keywords + */ struct pm_node_list keywords; - /** ParametersNode#keyword_rest */ + /** + * ParametersNode#keyword_rest + */ struct pm_node *keyword_rest; - /** ParametersNode#block */ + /** + * ParametersNode#block + */ struct pm_block_parameter_node *block; } pm_parameters_node_t; @@ -3636,13 +4557,19 @@ typedef struct pm_parentheses_node { /** The embedded base node. */ pm_node_t base; - /** ParenthesesNode#body */ + /** + * ParenthesesNode#body + */ struct pm_node *body; - /** ParenthesesNode#opening_loc */ + /** + * ParenthesesNode#opening_loc + */ pm_location_t opening_loc; - /** ParenthesesNode#closing_loc */ + /** + * ParenthesesNode#closing_loc + */ pm_location_t closing_loc; } pm_parentheses_node_t; @@ -3657,16 +4584,24 @@ typedef struct pm_pinned_expression_node { /** The embedded base node. */ pm_node_t base; - /** PinnedExpressionNode#expression */ + /** + * PinnedExpressionNode#expression + */ struct pm_node *expression; - /** PinnedExpressionNode#operator_loc */ + /** + * PinnedExpressionNode#operator_loc + */ pm_location_t operator_loc; - /** PinnedExpressionNode#lparen_loc */ + /** + * PinnedExpressionNode#lparen_loc + */ pm_location_t lparen_loc; - /** PinnedExpressionNode#rparen_loc */ + /** + * PinnedExpressionNode#rparen_loc + */ pm_location_t rparen_loc; } pm_pinned_expression_node_t; @@ -3681,10 +4616,14 @@ typedef struct pm_pinned_variable_node { /** The embedded base node. */ pm_node_t base; - /** PinnedVariableNode#variable */ + /** + * PinnedVariableNode#variable + */ struct pm_node *variable; - /** PinnedVariableNode#operator_loc */ + /** + * PinnedVariableNode#operator_loc + */ pm_location_t operator_loc; } pm_pinned_variable_node_t; @@ -3699,16 +4638,24 @@ typedef struct pm_post_execution_node { /** The embedded base node. */ pm_node_t base; - /** PostExecutionNode#statements */ + /** + * PostExecutionNode#statements + */ struct pm_statements_node *statements; - /** PostExecutionNode#keyword_loc */ + /** + * PostExecutionNode#keyword_loc + */ pm_location_t keyword_loc; - /** PostExecutionNode#opening_loc */ + /** + * PostExecutionNode#opening_loc + */ pm_location_t opening_loc; - /** PostExecutionNode#closing_loc */ + /** + * PostExecutionNode#closing_loc + */ pm_location_t closing_loc; } pm_post_execution_node_t; @@ -3723,16 +4670,24 @@ typedef struct pm_pre_execution_node { /** The embedded base node. */ pm_node_t base; - /** PreExecutionNode#statements */ + /** + * PreExecutionNode#statements + */ struct pm_statements_node *statements; - /** PreExecutionNode#keyword_loc */ + /** + * PreExecutionNode#keyword_loc + */ pm_location_t keyword_loc; - /** PreExecutionNode#opening_loc */ + /** + * PreExecutionNode#opening_loc + */ pm_location_t opening_loc; - /** PreExecutionNode#closing_loc */ + /** + * PreExecutionNode#closing_loc + */ pm_location_t closing_loc; } pm_pre_execution_node_t; @@ -3747,10 +4702,14 @@ typedef struct pm_program_node { /** The embedded base node. */ pm_node_t base; - /** ProgramNode#locals */ + /** + * ProgramNode#locals + */ pm_constant_id_list_t locals; - /** ProgramNode#statements */ + /** + * ProgramNode#statements + */ struct pm_statements_node *statements; } pm_program_node_t; @@ -3767,13 +4726,19 @@ typedef struct pm_range_node { /** The embedded base node. */ pm_node_t base; - /** RangeNode#left */ + /** + * RangeNode#left + */ struct pm_node *left; - /** RangeNode#right */ + /** + * RangeNode#right + */ struct pm_node *right; - /** RangeNode#operator_loc */ + /** + * RangeNode#operator_loc + */ pm_location_t operator_loc; } pm_range_node_t; @@ -3788,7 +4753,9 @@ typedef struct pm_rational_node { /** The embedded base node. */ pm_node_t base; - /** RationalNode#numeric */ + /** + * RationalNode#numeric + */ struct pm_node *numeric; } pm_rational_node_t; @@ -3817,6 +4784,9 @@ typedef struct pm_redo_node { * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -3824,16 +4794,24 @@ typedef struct pm_regular_expression_node { /** The embedded base node. */ pm_node_t base; - /** RegularExpressionNode#opening_loc */ + /** + * RegularExpressionNode#opening_loc + */ pm_location_t opening_loc; - /** RegularExpressionNode#content_loc */ + /** + * RegularExpressionNode#content_loc + */ pm_location_t content_loc; - /** RegularExpressionNode#closing_loc */ + /** + * RegularExpressionNode#closing_loc + */ pm_location_t closing_loc; - /** RegularExpressionNode#unescaped */ + /** + * RegularExpressionNode#unescaped + */ pm_string_t unescaped; } pm_regular_expression_node_t; @@ -3848,10 +4826,14 @@ typedef struct pm_required_keyword_parameter_node { /** The embedded base node. */ pm_node_t base; - /** RequiredKeywordParameterNode#name */ + /** + * RequiredKeywordParameterNode#name + */ pm_constant_id_t name; - /** RequiredKeywordParameterNode#name_loc */ + /** + * RequiredKeywordParameterNode#name_loc + */ pm_location_t name_loc; } pm_required_keyword_parameter_node_t; @@ -3866,7 +4848,9 @@ typedef struct pm_required_parameter_node { /** The embedded base node. */ pm_node_t base; - /** RequiredParameterNode#name */ + /** + * RequiredParameterNode#name + */ pm_constant_id_t name; } pm_required_parameter_node_t; @@ -3881,13 +4865,19 @@ typedef struct pm_rescue_modifier_node { /** The embedded base node. */ pm_node_t base; - /** RescueModifierNode#expression */ + /** + * RescueModifierNode#expression + */ struct pm_node *expression; - /** RescueModifierNode#keyword_loc */ + /** + * RescueModifierNode#keyword_loc + */ pm_location_t keyword_loc; - /** RescueModifierNode#rescue_expression */ + /** + * RescueModifierNode#rescue_expression + */ struct pm_node *rescue_expression; } pm_rescue_modifier_node_t; @@ -3902,22 +4892,34 @@ typedef struct pm_rescue_node { /** The embedded base node. */ pm_node_t base; - /** RescueNode#keyword_loc */ + /** + * RescueNode#keyword_loc + */ pm_location_t keyword_loc; - /** RescueNode#exceptions */ + /** + * RescueNode#exceptions + */ struct pm_node_list exceptions; - /** RescueNode#operator_loc */ + /** + * RescueNode#operator_loc + */ pm_location_t operator_loc; - /** RescueNode#reference */ + /** + * RescueNode#reference + */ struct pm_node *reference; - /** RescueNode#statements */ + /** + * RescueNode#statements + */ struct pm_statements_node *statements; - /** RescueNode#consequent */ + /** + * RescueNode#consequent + */ struct pm_rescue_node *consequent; } pm_rescue_node_t; @@ -3932,13 +4934,19 @@ typedef struct pm_rest_parameter_node { /** The embedded base node. */ pm_node_t base; - /** RestParameterNode#name */ + /** + * RestParameterNode#name + */ pm_constant_id_t name; - /** RestParameterNode#name_loc */ + /** + * RestParameterNode#name_loc + */ pm_location_t name_loc; - /** RestParameterNode#operator_loc */ + /** + * RestParameterNode#operator_loc + */ pm_location_t operator_loc; } pm_rest_parameter_node_t; @@ -3965,10 +4973,14 @@ typedef struct pm_return_node { /** The embedded base node. */ pm_node_t base; - /** ReturnNode#keyword_loc */ + /** + * ReturnNode#keyword_loc + */ pm_location_t keyword_loc; - /** ReturnNode#arguments */ + /** + * ReturnNode#arguments + */ struct pm_arguments_node *arguments; } pm_return_node_t; @@ -3995,22 +5007,34 @@ typedef struct pm_singleton_class_node { /** The embedded base node. */ pm_node_t base; - /** SingletonClassNode#locals */ + /** + * SingletonClassNode#locals + */ pm_constant_id_list_t locals; - /** SingletonClassNode#class_keyword_loc */ + /** + * SingletonClassNode#class_keyword_loc + */ pm_location_t class_keyword_loc; - /** SingletonClassNode#operator_loc */ + /** + * SingletonClassNode#operator_loc + */ pm_location_t operator_loc; - /** SingletonClassNode#expression */ + /** + * SingletonClassNode#expression + */ struct pm_node *expression; - /** SingletonClassNode#body */ + /** + * SingletonClassNode#body + */ struct pm_node *body; - /** SingletonClassNode#end_keyword_loc */ + /** + * SingletonClassNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_singleton_class_node_t; @@ -4037,7 +5061,9 @@ typedef struct pm_source_file_node { /** The embedded base node. */ pm_node_t base; - /** SourceFileNode#filepath */ + /** + * SourceFileNode#filepath + */ pm_string_t filepath; } pm_source_file_node_t; @@ -4064,10 +5090,14 @@ typedef struct pm_splat_node { /** The embedded base node. */ pm_node_t base; - /** SplatNode#operator_loc */ + /** + * SplatNode#operator_loc + */ pm_location_t operator_loc; - /** SplatNode#expression */ + /** + * SplatNode#expression + */ struct pm_node *expression; } pm_splat_node_t; @@ -4082,7 +5112,9 @@ typedef struct pm_statements_node { /** The embedded base node. */ pm_node_t base; - /** StatementsNode#body */ + /** + * StatementsNode#body + */ struct pm_node_list body; } pm_statements_node_t; @@ -4091,6 +5123,8 @@ typedef struct pm_statements_node { * * Type: PM_STRING_NODE * Flags: + * PM_STRING_FLAGS_FORCED_UTF8_ENCODING + * PM_STRING_FLAGS_FORCED_BINARY_ENCODING * PM_STRING_FLAGS_FROZEN * * @extends pm_node_t @@ -4099,16 +5133,24 @@ typedef struct pm_string_node { /** The embedded base node. */ pm_node_t base; - /** StringNode#opening_loc */ + /** + * StringNode#opening_loc + */ pm_location_t opening_loc; - /** StringNode#content_loc */ + /** + * StringNode#content_loc + */ pm_location_t content_loc; - /** StringNode#closing_loc */ + /** + * StringNode#closing_loc + */ pm_location_t closing_loc; - /** StringNode#unescaped */ + /** + * StringNode#unescaped + */ pm_string_t unescaped; } pm_string_node_t; @@ -4123,19 +5165,29 @@ typedef struct pm_super_node { /** The embedded base node. */ pm_node_t base; - /** SuperNode#keyword_loc */ + /** + * SuperNode#keyword_loc + */ pm_location_t keyword_loc; - /** SuperNode#lparen_loc */ + /** + * SuperNode#lparen_loc + */ pm_location_t lparen_loc; - /** SuperNode#arguments */ + /** + * SuperNode#arguments + */ struct pm_arguments_node *arguments; - /** SuperNode#rparen_loc */ + /** + * SuperNode#rparen_loc + */ pm_location_t rparen_loc; - /** SuperNode#block */ + /** + * SuperNode#block + */ struct pm_node *block; } pm_super_node_t; @@ -4143,6 +5195,10 @@ typedef struct pm_super_node { * SymbolNode * * Type: PM_SYMBOL_NODE + * Flags: + * PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING + * PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING + * PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -4150,16 +5206,24 @@ typedef struct pm_symbol_node { /** The embedded base node. */ pm_node_t base; - /** SymbolNode#opening_loc */ + /** + * SymbolNode#opening_loc + */ pm_location_t opening_loc; - /** SymbolNode#value_loc */ + /** + * SymbolNode#value_loc + */ pm_location_t value_loc; - /** SymbolNode#closing_loc */ + /** + * SymbolNode#closing_loc + */ pm_location_t closing_loc; - /** SymbolNode#unescaped */ + /** + * SymbolNode#unescaped + */ pm_string_t unescaped; } pm_symbol_node_t; @@ -4186,10 +5250,14 @@ typedef struct pm_undef_node { /** The embedded base node. */ pm_node_t base; - /** UndefNode#names */ + /** + * UndefNode#names + */ struct pm_node_list names; - /** UndefNode#keyword_loc */ + /** + * UndefNode#keyword_loc + */ pm_location_t keyword_loc; } pm_undef_node_t; @@ -4204,22 +5272,34 @@ typedef struct pm_unless_node { /** The embedded base node. */ pm_node_t base; - /** UnlessNode#keyword_loc */ + /** + * UnlessNode#keyword_loc + */ pm_location_t keyword_loc; - /** UnlessNode#predicate */ + /** + * UnlessNode#predicate + */ struct pm_node *predicate; - /** UnlessNode#then_keyword_loc */ + /** + * UnlessNode#then_keyword_loc + */ pm_location_t then_keyword_loc; - /** UnlessNode#statements */ + /** + * UnlessNode#statements + */ struct pm_statements_node *statements; - /** UnlessNode#consequent */ + /** + * UnlessNode#consequent + */ struct pm_else_node *consequent; - /** UnlessNode#end_keyword_loc */ + /** + * UnlessNode#end_keyword_loc + */ pm_location_t end_keyword_loc; } pm_unless_node_t; @@ -4236,16 +5316,24 @@ typedef struct pm_until_node { /** The embedded base node. */ pm_node_t base; - /** UntilNode#keyword_loc */ + /** + * UntilNode#keyword_loc + */ pm_location_t keyword_loc; - /** UntilNode#closing_loc */ + /** + * UntilNode#closing_loc + */ pm_location_t closing_loc; - /** UntilNode#predicate */ + /** + * UntilNode#predicate + */ struct pm_node *predicate; - /** UntilNode#statements */ + /** + * UntilNode#statements + */ struct pm_statements_node *statements; } pm_until_node_t; @@ -4260,13 +5348,19 @@ typedef struct pm_when_node { /** The embedded base node. */ pm_node_t base; - /** WhenNode#keyword_loc */ + /** + * WhenNode#keyword_loc + */ pm_location_t keyword_loc; - /** WhenNode#conditions */ + /** + * WhenNode#conditions + */ struct pm_node_list conditions; - /** WhenNode#statements */ + /** + * WhenNode#statements + */ struct pm_statements_node *statements; } pm_when_node_t; @@ -4283,16 +5377,24 @@ typedef struct pm_while_node { /** The embedded base node. */ pm_node_t base; - /** WhileNode#keyword_loc */ + /** + * WhileNode#keyword_loc + */ pm_location_t keyword_loc; - /** WhileNode#closing_loc */ + /** + * WhileNode#closing_loc + */ pm_location_t closing_loc; - /** WhileNode#predicate */ + /** + * WhileNode#predicate + */ struct pm_node *predicate; - /** WhileNode#statements */ + /** + * WhileNode#statements + */ struct pm_statements_node *statements; } pm_while_node_t; @@ -4300,6 +5402,9 @@ typedef struct pm_while_node { * XStringNode * * Type: PM_X_STRING_NODE + * Flags: + * PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING + * PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING * * @extends pm_node_t */ @@ -4307,16 +5412,24 @@ typedef struct pm_x_string_node { /** The embedded base node. */ pm_node_t base; - /** XStringNode#opening_loc */ + /** + * XStringNode#opening_loc + */ pm_location_t opening_loc; - /** XStringNode#content_loc */ + /** + * XStringNode#content_loc + */ pm_location_t content_loc; - /** XStringNode#closing_loc */ + /** + * XStringNode#closing_loc + */ pm_location_t closing_loc; - /** XStringNode#unescaped */ + /** + * XStringNode#unescaped + */ pm_string_t unescaped; } pm_x_string_node_t; @@ -4331,16 +5444,24 @@ typedef struct pm_yield_node { /** The embedded base node. */ pm_node_t base; - /** YieldNode#keyword_loc */ + /** + * YieldNode#keyword_loc + */ pm_location_t keyword_loc; - /** YieldNode#lparen_loc */ + /** + * YieldNode#lparen_loc + */ pm_location_t lparen_loc; - /** YieldNode#arguments */ + /** + * YieldNode#arguments + */ struct pm_arguments_node *arguments; - /** YieldNode#rparen_loc */ + /** + * YieldNode#rparen_loc + */ pm_location_t rparen_loc; } pm_yield_node_t; @@ -4369,8 +5490,25 @@ typedef enum pm_call_node_flags { /** a call that could have been a local variable */ PM_CALL_NODE_FLAGS_VARIABLE_CALL = 2, + + /** a call that is an attribute write, so the value being written should be returned */ + PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE = 4, + + /** a call that ignores method visibility */ + PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY = 8, } pm_call_node_flags_t; +/** + * Flags for nodes that have unescaped content. + */ +typedef enum pm_encoding_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING = 1, + + /** internal bytes forced the encoding to binary */ + PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING = 2, +} pm_encoding_flags_t; + /** * Flags for integer nodes that correspond to the base of the integer. */ @@ -4378,16 +5516,24 @@ typedef enum pm_integer_base_flags { /** 0b prefix */ PM_INTEGER_BASE_FLAGS_BINARY = 1, - /** 0o or 0 prefix */ - PM_INTEGER_BASE_FLAGS_OCTAL = 2, - /** 0d or no prefix */ - PM_INTEGER_BASE_FLAGS_DECIMAL = 4, + PM_INTEGER_BASE_FLAGS_DECIMAL = 2, + + /** 0o or 0 prefix */ + PM_INTEGER_BASE_FLAGS_OCTAL = 4, /** 0x prefix */ PM_INTEGER_BASE_FLAGS_HEXADECIMAL = 8, } pm_integer_base_flags_t; +/** + * Flags for keyword hash nodes. + */ +typedef enum pm_keyword_hash_node_flags { + /** a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments */ + PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS = 1, +} pm_keyword_hash_node_flags_t; + /** * Flags for while and until loop nodes. */ @@ -4431,16 +5577,45 @@ typedef enum pm_regular_expression_flags { /** u - forces the UTF-8 encoding */ PM_REGULAR_EXPRESSION_FLAGS_UTF_8 = 128, + + /** internal bytes forced the encoding to UTF-8 */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING = 256, + + /** internal bytes forced the encoding to binary */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING = 512, + + /** internal bytes forced the encoding to US-ASCII */ + PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING = 1024, } pm_regular_expression_flags_t; /** * Flags for string nodes. */ typedef enum pm_string_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_STRING_FLAGS_FORCED_UTF8_ENCODING = 1, + + /** internal bytes forced the encoding to binary */ + PM_STRING_FLAGS_FORCED_BINARY_ENCODING = 2, + /** frozen by virtue of a `frozen_string_literal` comment */ - PM_STRING_FLAGS_FROZEN = 1, + PM_STRING_FLAGS_FROZEN = 4, } pm_string_flags_t; +/** + * Flags for symbol nodes. + */ +typedef enum pm_symbol_flags { + /** internal bytes forced the encoding to UTF-8 */ + PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING = 1, + + /** internal bytes forced the encoding to binary */ + PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING = 2, + + /** internal bytes forced the encoding to US-ASCII */ + PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING = 4, +} pm_symbol_flags_t; + /** * When we're serializing to Java, we want to skip serializing the location * fields as they won't be used by JRuby or TruffleRuby. This boolean allows us diff --git a/src/main/c/yarp/include/prism/defines.h b/src/main/c/yarp/include/prism/defines.h index f89a0bed8e49..c9715c4eb068 100644 --- a/src/main/c/yarp/include/prism/defines.h +++ b/src/main/c/yarp/include/prism/defines.h @@ -74,4 +74,21 @@ # define snprintf _snprintf #endif +/** + * A simple utility macro to concatenate two tokens together, necessary when one + * of the tokens is itself a macro. + */ +#define PM_CONCATENATE(left, right) left ## right + +/** + * We want to be able to use static assertions, but they weren't standardized + * until C11. As such, we polyfill it here by making a hacky typedef that will + * fail to compile due to a negative array size if the condition is false. + */ +#if defined(_Static_assert) +# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message) +#else +# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1] +#endif + #endif diff --git a/src/main/c/yarp/include/prism/diagnostic.h b/src/main/c/yarp/include/prism/diagnostic.h index 3614a38ae79c..da430b543851 100644 --- a/src/main/c/yarp/include/prism/diagnostic.h +++ b/src/main/c/yarp/include/prism/diagnostic.h @@ -6,6 +6,7 @@ #ifndef PRISM_DIAGNOSTIC_H #define PRISM_DIAGNOSTIC_H +#include "prism/ast.h" #include "prism/defines.h" #include "prism/util/pm_list.h" @@ -22,11 +23,8 @@ typedef struct { /** The embedded base node. */ pm_list_node_t node; - /** A pointer to the start of the source that generated the diagnostic. */ - const uint8_t *start; - - /** A pointer to the end of the source that generated the diagnostic. */ - const uint8_t *end; + /** The location of the diagnostic in the source. */ + pm_location_t location; /** The message associated with the diagnostic. */ const char *message; @@ -49,12 +47,14 @@ typedef enum { PM_ERR_ARGUMENT_AFTER_BLOCK, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES, PM_ERR_ARGUMENT_BARE_HASH, + PM_ERR_ARGUMENT_BLOCK_FORWARDING, PM_ERR_ARGUMENT_BLOCK_MULTI, PM_ERR_ARGUMENT_FORMAL_CLASS, PM_ERR_ARGUMENT_FORMAL_CONSTANT, PM_ERR_ARGUMENT_FORMAL_GLOBAL, PM_ERR_ARGUMENT_FORMAL_IVAR, PM_ERR_ARGUMENT_FORWARDING_UNBOUND, + PM_ERR_ARGUMENT_IN, PM_ERR_ARGUMENT_NO_FORWARDING_AMP, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, PM_ERR_ARGUMENT_NO_FORWARDING_STAR, @@ -179,11 +179,13 @@ typedef enum { PM_ERR_LIST_W_UPPER_ELEMENT, PM_ERR_LIST_W_UPPER_TERM, PM_ERR_MALLOC_FAILED, + PM_ERR_MIXED_ENCODING, PM_ERR_MODULE_IN_METHOD, PM_ERR_MODULE_NAME, PM_ERR_MODULE_TERM, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS, PM_ERR_NOT_EXPRESSION, + PM_ERR_NO_LOCAL_VARIABLE, PM_ERR_NUMBER_LITERAL_UNDERSCORE, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE, @@ -212,6 +214,7 @@ typedef enum { PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, + PM_ERR_PATTERN_EXPRESSION_AFTER_REST, PM_ERR_PATTERN_HASH_KEY, PM_ERR_PATTERN_HASH_KEY_LABEL, PM_ERR_PATTERN_IDENT_AFTER_HROCKET, @@ -248,6 +251,7 @@ typedef enum { PM_ERR_UNTIL_TERM, PM_ERR_VOID_EXPRESSION, PM_ERR_WHILE_TERM, + PM_ERR_WRITE_TARGET_IN_METHOD, PM_ERR_WRITE_TARGET_READONLY, PM_ERR_WRITE_TARGET_UNEXPECTED, PM_ERR_XSTRING_TERM, diff --git a/src/main/c/yarp/include/prism/encoding.h b/src/main/c/yarp/include/prism/encoding.h index 247db600ce7a..8fe01aea69b4 100644 --- a/src/main/c/yarp/include/prism/encoding.h +++ b/src/main/c/yarp/include/prism/encoding.h @@ -121,11 +121,10 @@ bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n); extern const uint8_t pm_encoding_unicode_table[256]; /** - * These are all of the encodings that prisms supports. + * These are all of the encodings that prism supports. */ typedef enum { PM_ENCODING_UTF_8 = 0, - PM_ENCODING_ASCII, PM_ENCODING_ASCII_8BIT, PM_ENCODING_BIG5, PM_ENCODING_BIG5_HKSCS, @@ -199,6 +198,7 @@ typedef enum { PM_ENCODING_STATELESS_ISO_2022_JP, PM_ENCODING_STATELESS_ISO_2022_JP_KDDI, PM_ENCODING_TIS_620, + PM_ENCODING_US_ASCII, PM_ENCODING_UTF8_MAC, PM_ENCODING_UTF8_DOCOMO, PM_ENCODING_UTF8_KDDI, @@ -213,13 +213,27 @@ typedef enum { PM_ENCODING_WINDOWS_1257, PM_ENCODING_WINDOWS_1258, PM_ENCODING_WINDOWS_31J, - PM_ENCODING_WINDOWS_874 + PM_ENCODING_WINDOWS_874, + PM_ENCODING_MAXIMUM } pm_encoding_type_t; /** - * This is the default UTF-8 encoding. We need it to quickly create parsers. + * This is the table of all of the encodings that prism supports. */ -extern const pm_encoding_t *pm_encoding_utf_8; +extern const pm_encoding_t pm_encodings[PM_ENCODING_MAXIMUM]; + +/** + * This is the default UTF-8 encoding. We need a reference to it to quickly + * create parsers. + */ +#define PM_ENCODING_UTF_8_ENTRY (&pm_encodings[PM_ENCODING_UTF_8]) + +/** + * This is the US-ASCII encoding. We need a reference to it to be able to + * compare against it when a string is being created because it could possibly + * need to fall back to ASCII-8BIT. + */ +#define PM_ENCODING_US_ASCII_ENTRY (&pm_encodings[PM_ENCODING_US_ASCII]) /** * Parse the given name of an encoding and return a pointer to the corresponding diff --git a/src/main/c/yarp/include/prism/options.h b/src/main/c/yarp/include/prism/options.h index 8608838da848..130d635b98e5 100644 --- a/src/main/c/yarp/include/prism/options.h +++ b/src/main/c/yarp/include/prism/options.h @@ -24,6 +24,19 @@ typedef struct pm_options_scope { pm_string_t *locals; } pm_options_scope_t; +/** + * The version of prism that we should be parsing with. This is used to allow + * consumers to specify which behavior they want in case they need to parse + * exactly as a specific version of CRuby. + */ +typedef enum { + /** The current version of prism. */ + PM_OPTIONS_VERSION_LATEST = 0, + + /** The vendored version of prism in CRuby 3.3.0. */ + PM_OPTIONS_VERSION_CRUBY_3_3_0 = 1 +} pm_options_version_t; + /** * The options that can be passed to the parser. */ @@ -55,6 +68,13 @@ typedef struct { */ pm_options_scope_t *scopes; + /** + * The version of prism that we should be parsing with. This is used to + * allow consumers to specify which behavior they want in case they need to + * parse exactly as a specific version of CRuby. + */ + pm_options_version_t version; + /** Whether or not the frozen string literal option has been set. */ bool frozen_string_literal; @@ -106,6 +126,18 @@ PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t * */ PRISM_EXPORTED_FUNCTION void pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings); +/** + * Set the version option on the given options struct by parsing the given + * string. If the string contains an invalid option, this returns false. + * Otherwise, it returns true. + * + * @param options The options struct to set the version on. + * @param version The version to set. + * @param length The length of the version string. + * @return Whether or not the version was parsed successfully. + */ +PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length); + /** * Allocate and zero out the scopes array on the given options struct. * @@ -167,9 +199,17 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options); * | ... | the encoding bytes | * | `1` | frozen string literal | * | `1` | suppress warnings | + * | `1` | the version | * | `4` | the number of scopes | * | ... | the scopes | * + * The version field is an enum, so it should be one of the following values: + * + * | value | version | + * | ----- | ------------------------- | + * | `0` | use the latest version of prism | + * | `1` | use the version of prism that is vendored in CRuby 3.3.0 | + * * Each scope is layed out as follows: * * | # bytes | field | diff --git a/src/main/c/yarp/include/prism/parser.h b/src/main/c/yarp/include/prism/parser.h index 237f9fead9c7..9f38dc583036 100644 --- a/src/main/c/yarp/include/prism/parser.h +++ b/src/main/c/yarp/include/prism/parser.h @@ -9,6 +9,7 @@ #include "prism/ast.h" #include "prism/defines.h" #include "prism/encoding.h" +#include "prism/options.h" #include "prism/util/pm_constant_pool.h" #include "prism/util/pm_list.h" #include "prism/util/pm_newline_list.h" @@ -382,11 +383,8 @@ typedef struct pm_comment { /** The embedded base node. */ pm_list_node_t node; - /** A pointer to the start of the comment in the source. */ - const uint8_t *start; - - /** A pointer to the end of the comment in the source. */ - const uint8_t *end; + /** The location of the comment in the source. */ + pm_location_t location; /** The type of comment that we've found. */ pm_comment_type_t type; @@ -526,12 +524,6 @@ struct pm_parser { size_t index; } lex_modes; - /** - * The common_whitespace value from the most-recently-popped heredoc mode of the lexer, so we - * can dedent the heredoc after popping the lex mode. - */ - size_t current_string_common_whitespace; - /** The pointer to the start of the source. */ const uint8_t *start; @@ -584,7 +576,7 @@ struct pm_parser { * The encoding functions for the current file is attached to the parser as * it's parsing so that it can change with a magic comment. */ - pm_encoding_t encoding; + const pm_encoding_t *encoding; /** * When the encoding that is being used to parse the source is changed by @@ -640,6 +632,43 @@ struct pm_parser { */ int32_t start_line; + /** + * When a string-like expression is being lexed, any byte or escape sequence + * that resolves to a value whose top bit is set (i.e., >= 0x80) will + * explicitly set the encoding to the same encoding as the source. + * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that + * resolves to a value whose top bit is set, then the encoding will be + * explicitly set to UTF-8. + * + * The _next_ time this happens, if the encoding that is about to become the + * explicitly set encoding does not match the previously set explicit + * encoding, a mixed encoding error will be emitted. + * + * When the expression is finished being lexed, the explicit encoding + * controls the encoding of the expression. For the most part this means + * that the expression will either be encoded in the source encoding or + * UTF-8. This holds for all encodings except US-ASCII. If the source is + * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the + * expression will be encoded as ASCII-8BIT. + * + * Note that if the expression is a list, different elements within the same + * list can have different encodings, so this will get reset between each + * element. Furthermore all of this only applies to lists that support + * interpolation, because otherwise escapes that could change the encoding + * are ignored. + * + * At first glance, it may make more sense for this to live on the lexer + * mode, but we need it here to communicate back to the parser for character + * literals that do not push a new lexer mode. + */ + const pm_encoding_t *explicit_encoding; + + /** The current parameter name id on parsing its default value. */ + pm_constant_id_t current_param_name; + + /** The version of prism that we should use to parse. */ + pm_options_version_t version; + /** Whether or not we're at the beginning of a command. */ bool command_start; @@ -662,9 +691,6 @@ struct pm_parser { /** This flag indicates that we are currently parsing a keyword argument. */ bool in_keyword_arg; - /** The current parameter name id on parsing its default value. */ - pm_constant_id_t current_param_name; - /** * Whether or not the parser has seen a token that has semantic meaning * (i.e., a token that is not a comment or whitespace). diff --git a/src/main/c/yarp/include/prism/util/pm_strpbrk.h b/src/main/c/yarp/include/prism/util/pm_strpbrk.h index 61a443e51adc..c1cf0d54dbe0 100644 --- a/src/main/c/yarp/include/prism/util/pm_strpbrk.h +++ b/src/main/c/yarp/include/prism/util/pm_strpbrk.h @@ -32,12 +32,12 @@ * need to take a slower path and iterate one multi-byte character at a time. * * @param parser The parser. - * @param source The source string. + * @param source The source to search. * @param charset The charset to search for. - * @param length The maximum length to search. + * @param length The maximum number of bytes to search. * @return A pointer to the first character in the source string that is in the * charset, or NULL if no such character exists. */ -const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length); +const uint8_t * pm_strpbrk(const pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length); #endif diff --git a/src/main/c/yarp/include/prism/version.h b/src/main/c/yarp/include/prism/version.h index 67a29ed38f95..1472c58be6f1 100644 --- a/src/main/c/yarp/include/prism/version.h +++ b/src/main/c/yarp/include/prism/version.h @@ -14,7 +14,7 @@ /** * The minor version of the Prism library as an int. */ -#define PRISM_VERSION_MINOR 18 +#define PRISM_VERSION_MINOR 19 /** * The patch version of the Prism library as an int. @@ -24,6 +24,6 @@ /** * The version of the Prism library as a constant string. */ -#define PRISM_VERSION "0.18.0" +#define PRISM_VERSION "0.19.0" #endif diff --git a/src/main/c/yarp/src/diagnostic.c b/src/main/c/yarp/src/diagnostic.c index 443ad35c6a46..c779955eb314 100644 --- a/src/main/c/yarp/src/diagnostic.c +++ b/src/main/c/yarp/src/diagnostic.c @@ -56,12 +56,14 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_ARGUMENT_AFTER_BLOCK] = "unexpected argument after a block argument", [PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = "unexpected argument after `...`", [PM_ERR_ARGUMENT_BARE_HASH] = "unexpected bare hash argument", + [PM_ERR_ARGUMENT_BLOCK_FORWARDING] = "both a block argument and a forwarding argument; only one block is allowed", [PM_ERR_ARGUMENT_BLOCK_MULTI] = "multiple block arguments; only one block is allowed", [PM_ERR_ARGUMENT_FORMAL_CLASS] = "invalid formal argument; formal argument cannot be a class variable", [PM_ERR_ARGUMENT_FORMAL_CONSTANT] = "invalid formal argument; formal argument cannot be a constant", [PM_ERR_ARGUMENT_FORMAL_GLOBAL] = "invalid formal argument; formal argument cannot be a global variable", [PM_ERR_ARGUMENT_FORMAL_IVAR] = "invalid formal argument; formal argument cannot be an instance variable", [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = "unexpected `...` in an non-parenthesized call", + [PM_ERR_ARGUMENT_IN] = "unexpected `in` keyword in arguments", [PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = "unexpected `&` when the parent method is not forwarding", [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "unexpected `...` when the parent method is not forwarding", [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = "unexpected `*` when the parent method is not forwarding", @@ -94,10 +96,10 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_CLASS_NAME] = "expected a constant name after `class`", [PM_ERR_CLASS_SUPERCLASS] = "expected a superclass after `<`", [PM_ERR_CLASS_TERM] = "expected an `end` to close the `class` statement", - [PM_ERR_CLASS_UNEXPECTED_END] = "unexpected `end`, expecting ';' or '\n'", + [PM_ERR_CLASS_UNEXPECTED_END] = "unexpected `end`, expecting ';' or '\\n'", [PM_ERR_CONDITIONAL_ELSIF_PREDICATE] = "expected a predicate expression for the `elsif` statement", [PM_ERR_CONDITIONAL_IF_PREDICATE] = "expected a predicate expression for the `if` statement", - [PM_ERR_CONDITIONAL_PREDICATE_TERM] = "expected `then` or `;` or '\n'", + [PM_ERR_CONDITIONAL_PREDICATE_TERM] = "expected `then` or `;` or '\\n'", [PM_ERR_CONDITIONAL_TERM] = "expected an `end` to close the conditional clause", [PM_ERR_CONDITIONAL_TERM_ELSE] = "expected an `end` to close the `else` clause", [PM_ERR_CONDITIONAL_UNLESS_PREDICATE] = "expected a predicate expression for the `unless` statement", @@ -185,13 +187,15 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_LIST_W_UPPER_ELEMENT] = "expected a string in a `%W` list", [PM_ERR_LIST_W_UPPER_TERM] = "expected a closing delimiter for the `%W` list", [PM_ERR_MALLOC_FAILED] = "failed to allocate memory", + [PM_ERR_MIXED_ENCODING] = "UTF-8 mixed within %s source", [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method definition", [PM_ERR_MODULE_NAME] = "expected a constant name after `module`", [PM_ERR_MODULE_TERM] = "expected an `end` to close the `module` statement", [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "multiple splats in multiple assignment", [PM_ERR_NOT_EXPRESSION] = "expected an expression after `not`", + [PM_ERR_NO_LOCAL_VARIABLE] = "%.*s: no such local variable", [PM_ERR_NUMBER_LITERAL_UNDERSCORE] = "number literal ending with a `_`", - [PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "numbered parameters are not allowed alongside explicit parameters", + [PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "numbered parameters are not allowed when an ordinary parameter is defined", [PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = "numbered parameter is already used in outer scope", [PM_ERR_OPERATOR_MULTI_ASSIGN] = "unexpected operator for a multiple assignment", [PM_ERR_OPERATOR_WRITE_ARGUMENTS] = "unexpected operator after a call with arguments", @@ -203,7 +207,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_PARAMETER_NAME_REPEAT] = "repeated parameter name", [PM_ERR_PARAMETER_NO_DEFAULT] = "expected a default value for the parameter", [PM_ERR_PARAMETER_NO_DEFAULT_KW] = "expected a default value for the keyword parameter", - [PM_ERR_PARAMETER_NUMBERED_RESERVED] = "%.2s is reserved for a numbered parameter", + [PM_ERR_PARAMETER_NUMBERED_RESERVED] = "%.2s is reserved for numbered parameters", [PM_ERR_PARAMETER_ORDER] = "unexpected parameter order", [PM_ERR_PARAMETER_SPLAT_MULTI] = "unexpected multiple `*` splat parameters", [PM_ERR_PARAMETER_STAR] = "unexpected parameter `*`", @@ -218,6 +222,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_PATTERN_EXPRESSION_AFTER_PIN] = "expected a pattern expression after the `^` pin operator", [PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = "expected a pattern expression after the `|` operator", [PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = "expected a pattern expression after the range operator", + [PM_ERR_PATTERN_EXPRESSION_AFTER_REST] = "unexpected pattern expression after the `**` expression", [PM_ERR_PATTERN_HASH_KEY] = "expected a key in the hash pattern", [PM_ERR_PATTERN_HASH_KEY_LABEL] = "expected a label as the key in the hash pattern", // TODO // THIS // AND // ABOVE // IS WEIRD [PM_ERR_PATTERN_IDENT_AFTER_HROCKET] = "expected an identifier after the `=>` operator", @@ -254,6 +259,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_UNTIL_TERM] = "expected an `end` to close the `until` statement", [PM_ERR_VOID_EXPRESSION] = "unexpected void value expression", [PM_ERR_WHILE_TERM] = "expected an `end` to close the `while` statement", + [PM_ERR_WRITE_TARGET_IN_METHOD] = "dynamic constant assignment", [PM_ERR_WRITE_TARGET_READONLY] = "immutable variable as a write target", [PM_ERR_WRITE_TARGET_UNEXPECTED] = "unexpected write target", [PM_ERR_XSTRING_TERM] = "expected a closing delimiter for the `%x` or backtick string", @@ -283,8 +289,7 @@ pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t * if (diagnostic == NULL) return false; *diagnostic = (pm_diagnostic_t) { - .start = start, - .end = end, + .location = { start, end }, .message = pm_diagnostic_message(diag_id), .owned = false }; @@ -327,8 +332,7 @@ pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const ui va_end(arguments); *diagnostic = (pm_diagnostic_t) { - .start = start, - .end = end, + .location = { start, end }, .message = message, .owned = true }; diff --git a/src/main/c/yarp/src/encoding.c b/src/main/c/yarp/src/encoding.c index 4bf6b6a775cf..2c6d7c97772c 100644 --- a/src/main/c/yarp/src/encoding.c +++ b/src/main/c/yarp/src/encoding.c @@ -4212,9 +4212,9 @@ pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) { } /** - * This is the definition of all of the encodings that we support. + * This is the table of all of the encodings that prism supports. */ -static const pm_encoding_t pm_encodings[] = { +const pm_encoding_t pm_encodings[] = { [PM_ENCODING_UTF_8] = { .name = "UTF-8", .char_width = pm_encoding_utf_8_char_width, @@ -4223,14 +4223,6 @@ static const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_utf_8_isupper_char, .multibyte = true }, - [PM_ENCODING_ASCII] = { - .name = "US-ASCII", - .char_width = pm_encoding_ascii_char_width, - .alnum_char = pm_encoding_ascii_alnum_char, - .alpha_char = pm_encoding_ascii_alpha_char, - .isupper_char = pm_encoding_ascii_isupper_char, - .multibyte = false - }, [PM_ENCODING_ASCII_8BIT] = { .name = "ASCII-8BIT", .char_width = pm_encoding_single_char_width, @@ -4815,6 +4807,14 @@ static const pm_encoding_t pm_encodings[] = { .isupper_char = pm_encoding_tis_620_isupper_char, .multibyte = false }, + [PM_ENCODING_US_ASCII] = { + .name = "US-ASCII", + .char_width = pm_encoding_ascii_char_width, + .alnum_char = pm_encoding_ascii_alnum_char, + .alpha_char = pm_encoding_ascii_alpha_char, + .isupper_char = pm_encoding_ascii_isupper_char, + .multibyte = false + }, [PM_ENCODING_UTF8_MAC] = { .name = "UTF8-MAC", .char_width = pm_encoding_utf_8_char_width, @@ -4937,11 +4937,6 @@ static const pm_encoding_t pm_encodings[] = { } }; -/** - * This is the default UTF-8 encoding. We need it to quickly create parsers. - */ -const pm_encoding_t *pm_encoding_utf_8 = pm_encodings; - /** * Parse the given name of an encoding and return a pointer to the corresponding * encoding struct if one can be found, otherwise return NULL. @@ -4961,7 +4956,7 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { } // Otherwise we'll return the default UTF-8 encoding. - return pm_encoding_utf_8; + return PM_ENCODING_UTF_8_ENTRY; } // Next, we're going to loop through each of the encodings that we handle @@ -4972,9 +4967,9 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { if (width >= 3) { switch (*start) { case 'A': case 'a': - ENCODING1("ASCII", PM_ENCODING_ASCII); + ENCODING1("ASCII", PM_ENCODING_US_ASCII); ENCODING1("ASCII-8BIT", PM_ENCODING_ASCII_8BIT); - ENCODING1("ANSI_X3.4-1968", PM_ENCODING_ASCII); + ENCODING1("ANSI_X3.4-1968", PM_ENCODING_US_ASCII); break; case 'B': case 'b': ENCODING1("BINARY", PM_ENCODING_ASCII_8BIT); @@ -5109,7 +5104,7 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("TIS-620", PM_ENCODING_TIS_620); break; case 'U': case 'u': - ENCODING1("US-ASCII", PM_ENCODING_ASCII); + ENCODING1("US-ASCII", PM_ENCODING_US_ASCII); ENCODING2("UTF8-MAC", "UTF-8-HFS", PM_ENCODING_UTF8_MAC); ENCODING1("UTF8-DoCoMo", PM_ENCODING_UTF8_DOCOMO); ENCODING1("UTF8-KDDI", PM_ENCODING_UTF8_KDDI); @@ -5129,7 +5124,7 @@ pm_encoding_find(const uint8_t *start, const uint8_t *end) { ENCODING1("Windows-1258", PM_ENCODING_WINDOWS_1258); break; case '6': - ENCODING1("646", PM_ENCODING_ASCII); + ENCODING1("646", PM_ENCODING_US_ASCII); break; } } diff --git a/src/main/c/yarp/src/node.c b/src/main/c/yarp/src/node.c index 118471d523b1..f05d66ce498d 100644 --- a/src/main/c/yarp/src/node.c +++ b/src/main/c/yarp/src/node.c @@ -237,6 +237,12 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { pm_node_destroy(parser, (pm_node_t *)cast->value); break; } +#line 58 "node.c.erb" + case PM_CALL_TARGET_NODE: { + pm_call_target_node_t *cast = (pm_call_target_node_t *) node; + pm_node_destroy(parser, (pm_node_t *)cast->receiver); + break; + } #line 58 "node.c.erb" case PM_CAPTURE_PATTERN_NODE: { pm_capture_pattern_node_t *cast = (pm_capture_pattern_node_t *) node; @@ -630,6 +636,18 @@ pm_node_destroy(pm_parser_t *parser, pm_node_t *node) { pm_node_destroy(parser, (pm_node_t *)cast->value); break; } +#line 58 "node.c.erb" + case PM_INDEX_TARGET_NODE: { + pm_index_target_node_t *cast = (pm_index_target_node_t *) node; + pm_node_destroy(parser, (pm_node_t *)cast->receiver); + if (cast->arguments != NULL) { + pm_node_destroy(parser, (pm_node_t *)cast->arguments); + } + if (cast->block != NULL) { + pm_node_destroy(parser, (pm_node_t *)cast->block); + } + break; + } #line 58 "node.c.erb" case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { pm_instance_variable_and_write_node_t *cast = (pm_instance_variable_and_write_node_t *) node; @@ -1345,6 +1363,13 @@ pm_node_memsize_node(pm_node_t *node, pm_memsize_t *memsize) { pm_node_memsize_node((pm_node_t *)cast->value, memsize); break; } +#line 103 "node.c.erb" + case PM_CALL_TARGET_NODE: { + pm_call_target_node_t *cast = (pm_call_target_node_t *) node; + memsize->memsize += sizeof(*cast); + pm_node_memsize_node((pm_node_t *)cast->receiver, memsize); + break; + } #line 103 "node.c.erb" case PM_CAPTURE_PATTERN_NODE: { pm_capture_pattern_node_t *cast = (pm_capture_pattern_node_t *) node; @@ -1815,6 +1840,19 @@ pm_node_memsize_node(pm_node_t *node, pm_memsize_t *memsize) { pm_node_memsize_node((pm_node_t *)cast->value, memsize); break; } +#line 103 "node.c.erb" + case PM_INDEX_TARGET_NODE: { + pm_index_target_node_t *cast = (pm_index_target_node_t *) node; + memsize->memsize += sizeof(*cast); + pm_node_memsize_node((pm_node_t *)cast->receiver, memsize); + if (cast->arguments != NULL) { + pm_node_memsize_node((pm_node_t *)cast->arguments, memsize); + } + if (cast->block != NULL) { + pm_node_memsize_node((pm_node_t *)cast->block, memsize); + } + break; + } #line 103 "node.c.erb" case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { pm_instance_variable_and_write_node_t *cast = (pm_instance_variable_and_write_node_t *) node; @@ -2493,6 +2531,8 @@ pm_node_type_to_str(pm_node_type_t node_type) return "PM_CALL_OPERATOR_WRITE_NODE"; case PM_CALL_OR_WRITE_NODE: return "PM_CALL_OR_WRITE_NODE"; + case PM_CALL_TARGET_NODE: + return "PM_CALL_TARGET_NODE"; case PM_CAPTURE_PATTERN_NODE: return "PM_CAPTURE_PATTERN_NODE"; case PM_CASE_MATCH_NODE: @@ -2597,6 +2637,8 @@ pm_node_type_to_str(pm_node_type_t node_type) return "PM_INDEX_OPERATOR_WRITE_NODE"; case PM_INDEX_OR_WRITE_NODE: return "PM_INDEX_OR_WRITE_NODE"; + case PM_INDEX_TARGET_NODE: + return "PM_INDEX_TARGET_NODE"; case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: return "PM_INSTANCE_VARIABLE_AND_WRITE_NODE"; case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: diff --git a/src/main/c/yarp/src/options.c b/src/main/c/yarp/src/options.c index 85d04d627254..0dcae0d16fc7 100644 --- a/src/main/c/yarp/src/options.c +++ b/src/main/c/yarp/src/options.c @@ -40,6 +40,33 @@ pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings) options->suppress_warnings = suppress_warnings; } +/** + * Set the version option on the given options struct by parsing the given + * string. If the string contains an invalid option, this returns false. + * Otherwise, it returns true. + */ +PRISM_EXPORTED_FUNCTION bool +pm_options_version_set(pm_options_t *options, const char *version, size_t length) { + if (version == NULL && length == 0) { + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } + + if (length == 5) { + if (strncmp(version, "3.3.0", 5) == 0) { + options->version = PM_OPTIONS_VERSION_CRUBY_3_3_0; + return true; + } + + if (strncmp(version, "latest", 6) == 0) { + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } + } + + return false; +} + /** * Allocate and zero out the scopes array on the given options struct. */ @@ -163,6 +190,7 @@ pm_options_read(pm_options_t *options, const char *data) { options->frozen_string_literal = *data++; options->suppress_warnings = *data++; + options->version = (pm_options_version_t) *data++; uint32_t scopes_count = pm_options_read_u32(data); data += 4; diff --git a/src/main/c/yarp/src/prettyprint.c b/src/main/c/yarp/src/prettyprint.c index 7550a4e60240..48796b81655e 100644 --- a/src/main/c/yarp/src/prettyprint.c +++ b/src/main/c/yarp/src/prettyprint.c @@ -251,16 +251,30 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " contains_keyword_splat", 23); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // arguments { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 arguments:", 20); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 arguments:", 20); pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast->arguments.size)); size_t last_index = cast->arguments.size; for (uint32_t index = 0; index < last_index; index++) { size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_append_string(prefix_buffer, " ", 4); pm_buffer_concat(output_buffer, prefix_buffer); if (index == last_index - 1) { @@ -276,28 +290,28 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } + break; + } + case PM_ARRAY_NODE: { + pm_array_node_t *cast = (pm_array_node_t *) node; + pm_buffer_append_string(output_buffer, "@ ArrayNode (location: ", 23); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; - if (cast->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT) { + if (cast->base.flags & PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT) { if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " contains_keyword_splat", 23); + pm_buffer_append_string(output_buffer, " contains_splat", 15); found = true; } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } - break; - } - case PM_ARRAY_NODE: { - pm_array_node_t *cast = (pm_array_node_t *) node; - pm_buffer_append_string(output_buffer, "@ ArrayNode (location: ", 23); - prettyprint_location(output_buffer, parser, &node->location); - pm_buffer_append_string(output_buffer, ")\n", 2); - // elements { pm_buffer_concat(output_buffer, prefix_buffer); @@ -342,7 +356,7 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // closing_loc { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); pm_location_t *location = &cast->closing_loc; if (location->start == NULL) { pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); @@ -355,20 +369,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " contains_splat", 15); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - break; } case PM_ARRAY_PATTERN_NODE: { @@ -783,6 +783,13 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "]\n", 2); } + // locals_body_index + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 locals_body_index:", 28); + pm_buffer_append_format(output_buffer, " %d\n", cast->locals_body_index); + } + // parameters { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1017,6 +1024,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1066,25 +1102,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // read_name { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1136,6 +1153,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1246,24 +1292,32 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // block { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 block:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 block:", 16); if (cast->block == NULL) { pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); } else { pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_append_string(prefix_buffer, " ", 4); pm_buffer_concat(output_buffer, prefix_buffer); prettyprint_node(output_buffer, parser, (pm_node_t *) cast->block, prefix_buffer); prefix_buffer->length = prefix_length; } } + break; + } + case PM_CALL_OPERATOR_WRITE_NODE: { + pm_call_operator_write_node_t *cast = (pm_call_operator_write_node_t *) node; + pm_buffer_append_string(output_buffer, "@ CallOperatorWriteNode (location: ", 35); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { if (found) pm_buffer_append_byte(output_buffer, ','); @@ -1275,18 +1329,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " variable_call", 14); found = true; } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } - break; - } - case PM_CALL_OPERATOR_WRITE_NODE: { - pm_call_operator_write_node_t *cast = (pm_call_operator_write_node_t *) node; - pm_buffer_append_string(output_buffer, "@ CallOperatorWriteNode (location: ", 35); - prettyprint_location(output_buffer, parser, &node->location); - pm_buffer_append_string(output_buffer, ")\n", 2); - // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1336,25 +1392,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // read_name { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1415,6 +1452,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1464,25 +1530,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // read_name { pm_buffer_concat(output_buffer, prefix_buffer); @@ -1528,35 +1575,118 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm break; } - case PM_CAPTURE_PATTERN_NODE: { - pm_capture_pattern_node_t *cast = (pm_capture_pattern_node_t *) node; - pm_buffer_append_string(output_buffer, "@ CapturePatternNode (location: ", 32); + case PM_CALL_TARGET_NODE: { + pm_call_target_node_t *cast = (pm_call_target_node_t *) node; + pm_buffer_append_string(output_buffer, "@ CallTargetNode (location: ", 28); prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); - // value + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 value:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); - - size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); - pm_buffer_concat(output_buffer, prefix_buffer); - prettyprint_node(output_buffer, parser, (pm_node_t *) cast->value, prefix_buffer); - prefix_buffer->length = prefix_length; } - // target + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 target:", 17); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 receiver:", 19); pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); pm_buffer_concat(output_buffer, prefix_buffer); - prettyprint_node(output_buffer, parser, (pm_node_t *) cast->target, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->receiver, prefix_buffer); + prefix_buffer->length = prefix_length; + } + + // call_operator_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 call_operator_loc:", 28); + pm_location_t *location = &cast->call_operator_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // name + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 name:", 15); + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_constant(output_buffer, parser, cast->name); + pm_buffer_append_byte(output_buffer, '\n'); + } + + // message_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 message_loc:", 22); + pm_location_t *location = &cast->message_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + break; + } + case PM_CAPTURE_PATTERN_NODE: { + pm_capture_pattern_node_t *cast = (pm_capture_pattern_node_t *) node; + pm_buffer_append_string(output_buffer, "@ CapturePatternNode (location: ", 32); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + + // value + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 value:", 16); + pm_buffer_append_byte(output_buffer, '\n'); + + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_concat(output_buffer, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->value, prefix_buffer); + prefix_buffer->length = prefix_length; + } + + // target + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 target:", 17); + pm_buffer_append_byte(output_buffer, '\n'); + + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_concat(output_buffer, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->target, prefix_buffer); prefix_buffer->length = prefix_length; } @@ -2777,6 +2907,13 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "]\n", 2); } + // locals_body_index + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 locals_body_index:", 28); + pm_buffer_append_format(output_buffer, " %d\n", cast->locals_body_index); + } + // def_keyword_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -3241,6 +3378,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_RANGE_FLAGS_EXCLUDE_END) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " exclude_end", 12); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // left { pm_buffer_concat(output_buffer, prefix_buffer); @@ -3278,7 +3429,7 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 operator_loc:", 23); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 operator_loc:", 23); pm_location_t *location = &cast->operator_loc; pm_buffer_append_byte(output_buffer, ' '); prettyprint_location(output_buffer, parser, location); @@ -3287,20 +3438,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "\"\n", 2); } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_RANGE_FLAGS_EXCLUDE_END) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " exclude_end", 12); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - break; } case PM_FLOAT_NODE: { @@ -4091,6 +4228,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4182,25 +4348,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4234,6 +4381,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4325,25 +4501,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // operator { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4386,6 +4543,35 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // receiver { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4477,25 +4663,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " safe_navigation", 16); - found = true; - } - if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " variable_call", 14); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4523,34 +4690,142 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm break; } - case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { - pm_instance_variable_and_write_node_t *cast = (pm_instance_variable_and_write_node_t *) node; - pm_buffer_append_string(output_buffer, "@ InstanceVariableAndWriteNode (location: ", 42); + case PM_INDEX_TARGET_NODE: { + pm_index_target_node_t *cast = (pm_index_target_node_t *) node; + pm_buffer_append_string(output_buffer, "@ IndexTargetNode (location: ", 29); prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); - // name - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 name:", 15); - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_constant(output_buffer, parser, cast->name); - pm_buffer_append_byte(output_buffer, '\n'); - } - - // name_loc + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 name_loc:", 19); - pm_location_t *location = &cast->name_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // operator_loc + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " safe_navigation", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " variable_call", 14); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " attribute_write", 16); + found = true; + } + if (cast->base.flags & PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " ignore_visibility", 18); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + + // receiver + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 receiver:", 19); + pm_buffer_append_byte(output_buffer, '\n'); + + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_concat(output_buffer, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->receiver, prefix_buffer); + prefix_buffer->length = prefix_length; + } + + // opening_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); + pm_location_t *location = &cast->opening_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // arguments + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 arguments:", 20); + if (cast->arguments == NULL) { + pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); + } else { + pm_buffer_append_byte(output_buffer, '\n'); + + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_concat(output_buffer, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->arguments, prefix_buffer); + prefix_buffer->length = prefix_length; + } + } + + // closing_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_location_t *location = &cast->closing_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // block + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 block:", 16); + if (cast->block == NULL) { + pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); + } else { + pm_buffer_append_byte(output_buffer, '\n'); + + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, " ", 4); + pm_buffer_concat(output_buffer, prefix_buffer); + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->block, prefix_buffer); + prefix_buffer->length = prefix_length; + } + } + + break; + } + case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { + pm_instance_variable_and_write_node_t *cast = (pm_instance_variable_and_write_node_t *) node; + pm_buffer_append_string(output_buffer, "@ InstanceVariableAndWriteNode (location: ", 42); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + + // name + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 name:", 15); + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_constant(output_buffer, parser, cast->name); + pm_buffer_append_byte(output_buffer, '\n'); + } + + // name_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 name_loc:", 19); + pm_location_t *location = &cast->name_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 operator_loc:", 23); @@ -4798,14 +5073,14 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " binary", 7); found = true; } - if (cast->base.flags & PM_INTEGER_BASE_FLAGS_OCTAL) { + if (cast->base.flags & PM_INTEGER_BASE_FLAGS_DECIMAL) { if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " octal", 6); + pm_buffer_append_string(output_buffer, " decimal", 8); found = true; } - if (cast->base.flags & PM_INTEGER_BASE_FLAGS_DECIMAL) { + if (cast->base.flags & PM_INTEGER_BASE_FLAGS_OCTAL) { if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " decimal", 8); + pm_buffer_append_string(output_buffer, " octal", 6); found = true; } if (cast->base.flags & PM_INTEGER_BASE_FLAGS_HEXADECIMAL) { @@ -4825,59 +5100,10 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); - // opening_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); - pm_location_t *location = &cast->opening_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // parts - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 parts:", 16); - pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast->parts.size)); - - size_t last_index = cast->parts.size; - for (uint32_t index = 0; index < last_index; index++) { - size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); - pm_buffer_concat(output_buffer, prefix_buffer); - - if (index == last_index - 1) { - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ", 10); - pm_buffer_append_string(prefix_buffer, " ", 4); - } else { - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ", 10); - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); - } - - prettyprint_node(output_buffer, parser, (pm_node_t *) cast->parts.nodes[index], prefix_buffer); - prefix_buffer->length = prefix_length; - } - } - - // closing_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); - pm_location_t *location = &cast->closing_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE) { if (found) pm_buffer_append_byte(output_buffer, ','); @@ -4919,18 +5145,25 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " utf_8", 6); found = true; } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_us_ascii_encoding", 25); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } - break; - } - case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { - pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) node; - pm_buffer_append_string(output_buffer, "@ InterpolatedRegularExpressionNode (location: ", 47); - prettyprint_location(output_buffer, parser, &node->location); - pm_buffer_append_string(output_buffer, ")\n", 2); - // opening_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -4971,7 +5204,7 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // closing_loc { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); pm_location_t *location = &cast->closing_loc; pm_buffer_append_byte(output_buffer, ' '); prettyprint_location(output_buffer, parser, location); @@ -4980,10 +5213,18 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "\"\n", 2); } + break; + } + case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { + pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) node; + pm_buffer_append_string(output_buffer, "@ InterpolatedRegularExpressionNode (location: ", 47); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE) { if (found) pm_buffer_append_byte(output_buffer, ','); @@ -5025,10 +5266,74 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " utf_8", 6); found = true; } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_us_ascii_encoding", 25); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } + // opening_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); + pm_location_t *location = &cast->opening_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // parts + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 parts:", 16); + pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast->parts.size)); + + size_t last_index = cast->parts.size; + for (uint32_t index = 0; index < last_index; index++) { + size_t prefix_length = prefix_buffer->length; + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_concat(output_buffer, prefix_buffer); + + if (index == last_index - 1) { + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ", 10); + pm_buffer_append_string(prefix_buffer, " ", 4); + } else { + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ", 10); + pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + } + + prettyprint_node(output_buffer, parser, (pm_node_t *) cast->parts.nodes[index], prefix_buffer); + prefix_buffer->length = prefix_length; + } + } + + // closing_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_location_t *location = &cast->closing_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + break; } case PM_INTERPOLATED_STRING_NODE: { @@ -5224,6 +5529,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " symbol_keys", 12); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // elements { pm_buffer_concat(output_buffer, prefix_buffer); @@ -5318,6 +5637,13 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "]\n", 2); } + // locals_body_index + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 locals_body_index:", 28); + pm_buffer_append_format(output_buffer, " %d\n", cast->locals_body_index); + } + // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -5697,55 +6023,10 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); - // opening_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); - pm_location_t *location = &cast->opening_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // content_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 content_loc:", 22); - pm_location_t *location = &cast->content_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // closing_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); - pm_location_t *location = &cast->closing_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // unescaped - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 unescaped:", 20); - pm_buffer_append_string(output_buffer, " \"", 2); - prettyprint_source(output_buffer, pm_string_source(&cast->unescaped), pm_string_length(&cast->unescaped)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE) { if (found) pm_buffer_append_byte(output_buffer, ','); @@ -5787,10 +6068,70 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " utf_8", 6); found = true; } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_us_ascii_encoding", 25); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } + // opening_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); + pm_location_t *location = &cast->opening_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // content_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 content_loc:", 22); + pm_location_t *location = &cast->content_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // closing_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_location_t *location = &cast->closing_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // unescaped + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unescaped:", 20); + pm_buffer_append_string(output_buffer, " \"", 2); + prettyprint_source(output_buffer, pm_string_source(&cast->unescaped), pm_string_length(&cast->unescaped)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + break; } case PM_MATCH_PREDICATE_NODE: { @@ -6967,6 +7308,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_RANGE_FLAGS_EXCLUDE_END) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " exclude_end", 12); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // left { pm_buffer_concat(output_buffer, prefix_buffer); @@ -7004,7 +7359,7 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // operator_loc { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 operator_loc:", 23); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 operator_loc:", 23); pm_location_t *location = &cast->operator_loc; pm_buffer_append_byte(output_buffer, ' '); prettyprint_location(output_buffer, parser, location); @@ -7013,20 +7368,6 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, "\"\n", 2); } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_RANGE_FLAGS_EXCLUDE_END) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " exclude_end", 12); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - break; } case PM_RATIONAL_NODE: { @@ -7063,55 +7404,10 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); - // opening_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); - pm_location_t *location = &cast->opening_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // content_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 content_loc:", 22); - pm_location_t *location = &cast->content_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // closing_loc - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); - pm_location_t *location = &cast->closing_loc; - pm_buffer_append_byte(output_buffer, ' '); - prettyprint_location(output_buffer, parser, location); - pm_buffer_append_string(output_buffer, " = \"", 4); - prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - - // unescaped - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 unescaped:", 20); - pm_buffer_append_string(output_buffer, " \"", 2); - prettyprint_source(output_buffer, pm_string_source(&cast->unescaped), pm_string_length(&cast->unescaped)); - pm_buffer_append_string(output_buffer, "\"\n", 2); - } - // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE) { if (found) pm_buffer_append_byte(output_buffer, ','); @@ -7153,10 +7449,70 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " utf_8", 6); found = true; } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } + if (cast->base.flags & PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_us_ascii_encoding", 25); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } + // opening_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 opening_loc:", 22); + pm_location_t *location = &cast->opening_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // content_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 content_loc:", 22); + pm_location_t *location = &cast->content_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // closing_loc + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 closing_loc:", 22); + pm_location_t *location = &cast->closing_loc; + pm_buffer_append_byte(output_buffer, ' '); + prettyprint_location(output_buffer, parser, location); + pm_buffer_append_string(output_buffer, " = \"", 4); + prettyprint_source(output_buffer, location->start, (size_t) (location->end - location->start)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + + // unescaped + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unescaped:", 20); + pm_buffer_append_string(output_buffer, " \"", 2); + prettyprint_source(output_buffer, pm_string_source(&cast->unescaped), pm_string_length(&cast->unescaped)); + pm_buffer_append_string(output_buffer, "\"\n", 2); + } + break; } case PM_REQUIRED_KEYWORD_PARAMETER_NODE: { @@ -7661,6 +8017,16 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_concat(output_buffer, prefix_buffer); pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; + if (cast->base.flags & PM_STRING_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_STRING_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } if (cast->base.flags & PM_STRING_FLAGS_FROZEN) { if (found) pm_buffer_append_byte(output_buffer, ','); pm_buffer_append_string(output_buffer, " frozen", 7); @@ -7817,6 +8183,30 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); + found = true; + } + if (cast->base.flags & PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_us_ascii_encoding", 25); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // opening_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -8033,6 +8423,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " begin_modifier", 15); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // keyword_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -8077,34 +8481,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // statements { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 statements:", 21); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 statements:", 21); if (cast->statements == NULL) { pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); } else { pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_append_string(prefix_buffer, " ", 4); pm_buffer_concat(output_buffer, prefix_buffer); prettyprint_node(output_buffer, parser, (pm_node_t *) cast->statements, prefix_buffer); prefix_buffer->length = prefix_length; } } - // flags - { - pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); - bool found = false; - if (cast->base.flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) { - if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " begin_modifier", 15); - found = true; - } - if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); - pm_buffer_append_byte(output_buffer, '\n'); - } - break; } case PM_WHEN_NODE: { @@ -8175,6 +8565,20 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm prettyprint_location(output_buffer, parser, &node->location); pm_buffer_append_string(output_buffer, ")\n", 2); + // flags + { + pm_buffer_concat(output_buffer, prefix_buffer); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); + bool found = false; + if (cast->base.flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " begin_modifier", 15); + found = true; + } + if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); + pm_buffer_append_byte(output_buffer, '\n'); + } + // keyword_loc { pm_buffer_concat(output_buffer, prefix_buffer); @@ -8219,42 +8623,47 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm // statements { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 statements:", 21); + pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 statements:", 21); if (cast->statements == NULL) { pm_buffer_append_string(output_buffer, " \xe2\x88\x85\n", 5); } else { pm_buffer_append_byte(output_buffer, '\n'); size_t prefix_length = prefix_buffer->length; - pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 6); + pm_buffer_append_string(prefix_buffer, " ", 4); pm_buffer_concat(output_buffer, prefix_buffer); prettyprint_node(output_buffer, parser, (pm_node_t *) cast->statements, prefix_buffer); prefix_buffer->length = prefix_length; } } + break; + } + case PM_X_STRING_NODE: { + pm_x_string_node_t *cast = (pm_x_string_node_t *) node; + pm_buffer_append_string(output_buffer, "@ XStringNode (location: ", 25); + prettyprint_location(output_buffer, parser, &node->location); + pm_buffer_append_string(output_buffer, ")\n", 2); + // flags { pm_buffer_concat(output_buffer, prefix_buffer); - pm_buffer_append_string(output_buffer, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 flags:", 16); + pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 flags:", 16); bool found = false; - if (cast->base.flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) { + if (cast->base.flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) { if (found) pm_buffer_append_byte(output_buffer, ','); - pm_buffer_append_string(output_buffer, " begin_modifier", 15); + pm_buffer_append_string(output_buffer, " forced_utf8_encoding", 21); + found = true; + } + if (cast->base.flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " forced_binary_encoding", 23); found = true; } if (!found) pm_buffer_append_string(output_buffer, " \xe2\x88\x85", 4); pm_buffer_append_byte(output_buffer, '\n'); } - break; - } - case PM_X_STRING_NODE: { - pm_x_string_node_t *cast = (pm_x_string_node_t *) node; - pm_buffer_append_string(output_buffer, "@ XStringNode (location: ", 25); - prettyprint_location(output_buffer, parser, &node->location); - pm_buffer_append_string(output_buffer, ")\n", 2); - // opening_loc { pm_buffer_concat(output_buffer, prefix_buffer); diff --git a/src/main/c/yarp/src/prism.c b/src/main/c/yarp/src/prism.c index 651a632079ed..5cefb1a86aa7 100644 --- a/src/main/c/yarp/src/prism.c +++ b/src/main/c/yarp/src/prism.c @@ -275,6 +275,7 @@ lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) { breakpoints[index++] = incrementor; } + parser->explicit_encoding = NULL; return lex_mode_push(parser, lex_mode); } @@ -356,6 +357,7 @@ lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed breakpoints[index++] = incrementor; } + parser->explicit_encoding = NULL; return lex_mode_push(parser, lex_mode); } @@ -539,7 +541,7 @@ pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_ * Append an error to the list of errors on the parser using the location of the * given token and a format string. */ -#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, token->start, token->end, diag_id, __VA_ARGS__) +#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, (token).start, (token).end, diag_id, __VA_ARGS__) /** * Append a warning to the list of warnings on the parser. @@ -811,6 +813,9 @@ typedef struct { /** The optional block attached to the call. */ pm_node_t *block; + + /** The flag indicating whether this arguments list has forwarding argument. */ + bool has_forwarding; } pm_arguments_t; /** @@ -862,6 +867,27 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK); } +/******************************************************************************/ +/* Node flag handling functions */ +/******************************************************************************/ + +/** + * Set the given flag on the given node. + */ +static inline void +pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) { + node->flags |= flag; +} + +/** + * Remove the given flag from the given node. + */ +static inline void +pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) { + node->flags &= (pm_node_flags_t) ~flag; +} + + /******************************************************************************/ /* Node creation functions */ /******************************************************************************/ @@ -1150,12 +1176,12 @@ pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) { // If the element is not a static literal, then the array is not a static // literal. Turn that flag off. - if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || (element->flags & PM_NODE_FLAG_STATIC_LITERAL) == 0) { - node->base.flags &= (pm_node_flags_t) ~PM_NODE_FLAG_STATIC_LITERAL; + if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) { + pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL); } if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) { - node->base.flags |= PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT; + pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT); } } @@ -1317,6 +1343,11 @@ pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *oper flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL; } + // Hash string keys should be frozen + if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) { + key->flags |= PM_STRING_FLAGS_FROZEN; + } + *node = (pm_assoc_node_t) { { .type = PM_ASSOC_NODE, @@ -1467,7 +1498,7 @@ pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, p * Allocate and initialize a new BlockNode node. */ static pm_block_node_t * -pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) { +pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, uint32_t locals_body_index, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) { pm_block_node_t *node = PM_ALLOC_NODE(parser, pm_block_node_t); *node = (pm_block_node_t) { @@ -1476,6 +1507,7 @@ pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p .location = { .start = opening->start, .end = closing->end }, }, .locals = *locals, + .locals_body_index = locals_body_index, .parameters = parameters, .body = body, .opening_loc = PM_LOCATION_TOKEN_VALUE(opening), @@ -1621,12 +1653,13 @@ pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argument * in the various specializations of this function. */ static pm_call_node_t * -pm_call_node_create(pm_parser_t *parser) { +pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) { pm_call_node_t *node = PM_ALLOC_NODE(parser, pm_call_node_t); *node = (pm_call_node_t) { { .type = PM_CALL_NODE, + .flags = flags, .location = PM_LOCATION_NULL_VALUE(parser), }, .receiver = NULL, @@ -1642,6 +1675,15 @@ pm_call_node_create(pm_parser_t *parser) { return node; } +/** + * Returns the value that the ignore visibility flag should be set to for the + * given receiver. + */ +static inline pm_node_flags_t +pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) { + return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0; +} + /** * Allocate and initialize a new CallNode node from an aref or an aset * expression. @@ -1650,7 +1692,7 @@ static pm_call_node_t * pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) { pm_assert_value_expression(parser, receiver); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = receiver->location.start; node->base.location.end = pm_arguments_end(arguments); @@ -1676,7 +1718,7 @@ pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t pm_assert_value_expression(parser, receiver); pm_assert_value_expression(parser, argument); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = MIN(receiver->location.start, argument->location.start); node->base.location.end = MAX(receiver->location.end, argument->location.end); @@ -1699,7 +1741,7 @@ static pm_call_node_t * pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) { pm_assert_value_expression(parser, receiver); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = receiver->location.start; const uint8_t *end = pm_arguments_end(arguments); @@ -1717,7 +1759,7 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o node->block = arguments->block; if (operator->type == PM_TOKEN_AMPERSAND_DOT) { - node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION; + pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION); } node->name = pm_parser_constant_id_token(parser, message); @@ -1730,7 +1772,7 @@ pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *o */ static pm_call_node_t * pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) { - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY); node->base.location.start = message->start; node->base.location.end = pm_arguments_end(arguments); @@ -1752,7 +1794,7 @@ static pm_call_node_t * pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) { pm_assert_value_expression(parser, receiver); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = message->start; if (arguments->closing_loc.start != NULL) { @@ -1778,7 +1820,7 @@ static pm_call_node_t * pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) { pm_assert_value_expression(parser, receiver); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = receiver->location.start; node->base.location.end = pm_arguments_end(arguments); @@ -1791,7 +1833,7 @@ pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token node->block = arguments->block; if (operator->type == PM_TOKEN_AMPERSAND_DOT) { - node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION; + pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION); } node->name = pm_parser_constant_id_constant(parser, "call", 4); @@ -1805,7 +1847,7 @@ static pm_call_node_t * pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) { pm_assert_value_expression(parser, receiver); - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver)); node->base.location.start = operator->start; node->base.location.end = receiver->location.end; @@ -1823,7 +1865,7 @@ pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t * */ static pm_call_node_t * pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) { - pm_call_node_t *node = pm_call_node_create(parser); + pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY); node->base.location = PM_LOCATION_TOKEN_VALUE(message); node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message); @@ -1838,7 +1880,7 @@ pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) { */ static inline bool pm_call_node_variable_call_p(pm_call_node_t *node) { - return node->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL; + return PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_VARIABLE_CALL); } /** @@ -2108,6 +2150,68 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const return node; } +/** + * Allocate and initialize a new CallTargetNode node from an existing call + * node. + */ +static pm_call_target_node_t * +pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { + pm_call_target_node_t *node = PM_ALLOC_NODE(parser, pm_call_target_node_t); + + *node = (pm_call_target_node_t) { + { + .type = PM_CALL_TARGET_NODE, + .flags = target->base.flags, + .location = target->base.location + }, + .receiver = target->receiver, + .call_operator_loc = target->call_operator_loc, + .name = target->name, + .message_loc = target->message_loc + }; + + // Here we're going to free the target, since it is no longer necessary. + // However, we don't want to call `pm_node_destroy` because we want to keep + // around all of its children since we just reused them. + free(target); + + return node; +} + +/** + * Allocate and initialize a new IndexTargetNode node from an existing call + * node. + */ +static pm_index_target_node_t * +pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { + pm_index_target_node_t *node = PM_ALLOC_NODE(parser, pm_index_target_node_t); + pm_node_flags_t flags = target->base.flags; + + if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) { + flags |= PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE; + } + + *node = (pm_index_target_node_t) { + { + .type = PM_INDEX_TARGET_NODE, + .flags = flags, + .location = target->base.location + }, + .receiver = target->receiver, + .opening_loc = target->opening_loc, + .arguments = target->arguments, + .closing_loc = target->closing_loc, + .block = target->block + }; + + // Here we're going to free the target, since it is no longer necessary. + // However, we don't want to call `pm_node_destroy` because we want to keep + // around all of its children since we just reused them. + free(target); + + return node; +} + /** * Allocate and initialize a new CapturePatternNode node. */ @@ -2631,6 +2735,7 @@ pm_def_node_create( pm_parameters_node_t *parameters, pm_node_t *body, pm_constant_id_list_t *locals, + uint32_t locals_body_index, const pm_token_t *def_keyword, const pm_token_t *operator, const pm_token_t *lparen, @@ -2658,6 +2763,7 @@ pm_def_node_create( .parameters = parameters, .body = body, .locals = *locals, + .locals_body_index = locals_body_index, .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword), .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator), .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen), @@ -3265,10 +3371,16 @@ static inline void pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) { pm_node_list_append(&hash->elements, element); - // If the element is not a static literal, then the hash is not a static - // literal. Turn that flag off. - if ((element->flags & PM_NODE_FLAG_STATIC_LITERAL) == 0) { - hash->base.flags &= (pm_node_flags_t) ~PM_NODE_FLAG_STATIC_LITERAL; + bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE); + if (static_literal) { + pm_assoc_node_t *assoc = (pm_assoc_node_t *) element; + static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE); + static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL); + static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL); + } + + if (!static_literal) { + pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL); } } @@ -3725,7 +3837,7 @@ static inline void pm_interpolated_regular_expression_node_closing_set(pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) { node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing); node->base.location.end = closing->end; - node->base.flags |= pm_regular_expression_flags_create(closing); + pm_node_flag_set((pm_node_t *)node, pm_regular_expression_flags_create(closing)); } /** @@ -3859,7 +3971,8 @@ pm_keyword_hash_node_create(pm_parser_t *parser) { *node = (pm_keyword_hash_node_t) { .base = { .type = PM_KEYWORD_HASH_NODE, - .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE + .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, + .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS }, .elements = { 0 } }; @@ -3872,6 +3985,13 @@ pm_keyword_hash_node_create(pm_parser_t *parser) { */ static void pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) { + // If the element being added is not an AssocNode or does not have a symbol key, then + // we want to turn the STATIC_KEYS flag off. + // TODO: Rename the flag to SYMBOL_KEYS instead. + if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) { + pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS); + } + pm_node_list_append(&hash->elements, element); if (hash->base.location.start == NULL) { hash->base.location.start = element->location.start; @@ -3954,6 +4074,7 @@ static pm_lambda_node_t * pm_lambda_node_create( pm_parser_t *parser, pm_constant_id_list_t *locals, + uint32_t locals_body_index, const pm_token_t *operator, const pm_token_t *opening, const pm_token_t *closing, @@ -3971,6 +4092,7 @@ pm_lambda_node_create( }, }, .locals = *locals, + .locals_body_index = locals_body_index, .operator_loc = PM_LOCATION_TOKEN_VALUE(operator), .opening_loc = PM_LOCATION_TOKEN_VALUE(opening), .closing_loc = PM_LOCATION_TOKEN_VALUE(closing), @@ -5190,7 +5312,7 @@ pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement) pm_node_list_append(&node->body, statement); // Every statement gets marked as a place where a newline can occur. - statement->flags |= PM_NODE_FLAG_NEWLINE; + pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE); } /** @@ -5709,6 +5831,7 @@ pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, *node = (pm_x_string_node_t) { { .type = PM_X_STRING_NODE, + .flags = PM_STRING_FLAGS_FROZEN, .location = { .start = opening->start, .end = closing->end @@ -5917,12 +6040,12 @@ static inline size_t char_is_identifier_start(pm_parser_t *parser, const uint8_t *b) { if (parser->encoding_changed) { size_t width; - if ((width = parser->encoding.alpha_char(b, parser->end - b)) != 0) { + if ((width = parser->encoding->alpha_char(b, parser->end - b)) != 0) { return width; } else if (*b == '_') { return 1; } else if (*b >= 0x80) { - return parser->encoding.char_width(b, parser->end - b); + return parser->encoding->char_width(b, parser->end - b); } else { return 0; } @@ -5955,12 +6078,12 @@ static inline size_t char_is_identifier(pm_parser_t *parser, const uint8_t *b) { if (parser->encoding_changed) { size_t width; - if ((width = parser->encoding.alnum_char(b, parser->end - b)) != 0) { + if ((width = parser->encoding->alnum_char(b, parser->end - b)) != 0) { return width; } else if (*b == '_') { return 1; } else if (*b >= 0x80) { - return parser->encoding.char_width(b, parser->end - b); + return parser->encoding->char_width(b, parser->end - b); } else { return 0; } @@ -6143,8 +6266,8 @@ parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *star const pm_encoding_t *encoding = pm_encoding_find(start, end); if (encoding != NULL) { - if (encoding != pm_encoding_utf_8) { - parser->encoding = *encoding; + if (encoding != PM_ENCODING_UTF_8_ENTRY) { + parser->encoding = encoding; parser->encoding_changed = true; if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser); } @@ -6200,7 +6323,7 @@ parser_lex_magic_comment_encoding(pm_parser_t *parser) { } const uint8_t *value_start = cursor; - while ((*cursor == '-' || *cursor == '_' || parser->encoding.alnum_char(cursor, 1)) && ++cursor < end); + while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end); if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) { // If we were unable to parse the encoding value, then we've got an @@ -6234,7 +6357,7 @@ pm_char_is_magic_comment_key_delimiter(const uint8_t b) { */ static inline const uint8_t * parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor, const uint8_t *end) { - while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor, '-', (size_t) (end - cursor), parser->encoding_changed, &parser->encoding)) != NULL) { + while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor, '-', (size_t) (end - cursor), parser->encoding_changed, parser->encoding)) != NULL) { if (cursor + 3 <= end && cursor[1] == '*' && cursor[2] == '-') { return cursor; } @@ -6324,7 +6447,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) { // underscores. We only need to do this if there _is_ a dash in the key. pm_string_t key; const size_t key_length = (size_t) (key_end - key_start); - const uint8_t *dash = pm_memchr(key_start, '-', (size_t) key_length, parser->encoding_changed, &parser->encoding); + const uint8_t *dash = pm_memchr(key_start, '-', (size_t) key_length, parser->encoding_changed, parser->encoding); if (dash == NULL) { pm_string_shared_init(&key, key_start, key_end); @@ -6336,7 +6459,7 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) { memcpy(buffer, key_start, width); buffer[dash - key_start] = '_'; - while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, &parser->encoding)) != NULL) { + while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) { buffer[dash - key_start] = '_'; } @@ -6995,7 +7118,7 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) { } if (encoding_changed) { - return parser->encoding.isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER; + return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER; } return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER; } @@ -7209,7 +7332,18 @@ escape_byte(uint8_t value, const uint8_t flags) { * Write a unicode codepoint to the given buffer. */ static inline void -escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t *start, const uint8_t *end, uint32_t value) { +escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, const uint8_t *start, const uint8_t *end, uint32_t value) { + // \u escape sequences in string-like structures implicitly change the + // encoding to UTF-8 if they are >= 0x80 or if they are used in a character + // literal. + if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) { + if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) { + PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name); + } + + parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY; + } + if (value <= 0x7F) { // 0xxxxxxx pm_buffer_append_byte(buffer, (uint8_t) value); } else if (value <= 0x7FF) { // 110xxxxx 10xxxxxx @@ -7232,6 +7366,23 @@ escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t *st } } +/** + * When you're writing a byte to the unescape buffer, if the byte is non-ASCII + * (i.e., the top bit is set) then it locks in the encoding. + */ +static inline void +escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t byte) { + if (byte >= 0x80) { + if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name); + } + + parser->explicit_encoding = parser->encoding; + } + + pm_buffer_append_byte(buffer, byte); +} + /** * The regular expression engine doesn't support the same escape sequences as * Ruby does. So first we have to read the escape sequence, and then we have to @@ -7248,7 +7399,7 @@ escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t *st * source so that the regular expression engine will perform its own unescaping. */ static inline void -escape_write_byte(pm_buffer_t *buffer, uint8_t flags, uint8_t byte) { +escape_write_byte(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags, uint8_t byte) { if (flags & PM_ESCAPE_FLAG_REGEXP) { pm_buffer_append_bytes(buffer, (const uint8_t *) "\\x", 2); @@ -7267,7 +7418,7 @@ escape_write_byte(pm_buffer_t *buffer, uint8_t flags, uint8_t byte) { pm_buffer_append_byte(buffer, (uint8_t) (byte2 + '0')); } } else { - pm_buffer_append_byte(buffer, byte); + escape_write_byte_encoded(parser, buffer, byte); } } @@ -7279,57 +7430,57 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { switch (peek(parser)) { case '\\': { parser->current.end++; - pm_buffer_append_byte(buffer, '\\'); + escape_write_byte_encoded(parser, buffer, escape_byte('\\', flags)); return; } case '\'': { parser->current.end++; - pm_buffer_append_byte(buffer, '\''); + escape_write_byte_encoded(parser, buffer, escape_byte('\'', flags)); return; } case 'a': { parser->current.end++; - pm_buffer_append_byte(buffer, '\a'); + escape_write_byte_encoded(parser, buffer, escape_byte('\a', flags)); return; } case 'b': { parser->current.end++; - pm_buffer_append_byte(buffer, '\b'); + escape_write_byte_encoded(parser, buffer, escape_byte('\b', flags)); return; } case 'e': { parser->current.end++; - pm_buffer_append_byte(buffer, '\033'); + escape_write_byte_encoded(parser, buffer, escape_byte('\033', flags)); return; } case 'f': { parser->current.end++; - pm_buffer_append_byte(buffer, '\f'); + escape_write_byte_encoded(parser, buffer, escape_byte('\f', flags)); return; } case 'n': { parser->current.end++; - pm_buffer_append_byte(buffer, '\n'); + escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags)); return; } case 'r': { parser->current.end++; - pm_buffer_append_byte(buffer, '\r'); + escape_write_byte_encoded(parser, buffer, escape_byte('\r', flags)); return; } case 's': { parser->current.end++; - pm_buffer_append_byte(buffer, ' '); + escape_write_byte_encoded(parser, buffer, escape_byte(' ', flags)); return; } case 't': { parser->current.end++; - pm_buffer_append_byte(buffer, '\t'); + escape_write_byte_encoded(parser, buffer, escape_byte('\t', flags)); return; } case 'v': { parser->current.end++; - pm_buffer_append_byte(buffer, '\v'); + escape_write_byte_encoded(parser, buffer, escape_byte('\v', flags)); return; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { @@ -7346,7 +7497,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { } } - pm_buffer_append_byte(buffer, value); + escape_write_byte_encoded(parser, buffer, value); return; } case 'x': { @@ -7368,7 +7519,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { if (flags & PM_ESCAPE_FLAG_REGEXP) { pm_buffer_append_bytes(buffer, start, (size_t) (parser->current.end - start)); } else { - pm_buffer_append_byte(buffer, value); + escape_write_byte_encoded(parser, buffer, value); } } else { pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL); @@ -7392,7 +7543,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { if (flags & PM_ESCAPE_FLAG_REGEXP) { pm_buffer_append_bytes(buffer, start, (size_t) (parser->current.end + 4 - start)); } else { - escape_write_unicode(parser, buffer, start, parser->current.end + 4, value); + escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value); } parser->current.end += 4; @@ -7426,13 +7577,14 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { if (!(flags & PM_ESCAPE_FLAG_REGEXP)) { uint32_t value = escape_unicode(unicode_start, hexadecimal_length); - escape_write_unicode(parser, buffer, unicode_start, parser->current.end, value); + escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value); } parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end); } - // ?\u{nnnn} character literal should contain only one codepoint and cannot be like ?\u{nnnn mmmm} + // ?\u{nnnn} character literal should contain only one codepoint + // and cannot be like ?\u{nnnn mmmm}. if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) { pm_parser_err(parser, extra_codepoints_start, parser->current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL); } @@ -7463,7 +7615,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { switch (peeked) { case '?': { parser->current.end++; - escape_write_byte(buffer, flags, escape_byte(0x7f, flags)); + escape_write_byte(parser, buffer, flags, escape_byte(0x7f, flags)); return; } case '\\': @@ -7481,7 +7633,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { } parser->current.end++; - escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL)); + escape_write_byte(parser, buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL)); return; } } @@ -7503,7 +7655,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { switch (peeked) { case '?': { parser->current.end++; - escape_write_byte(buffer, flags, escape_byte(0x7f, flags)); + escape_write_byte(parser, buffer, flags, escape_byte(0x7f, flags)); return; } case '\\': @@ -7521,7 +7673,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { } parser->current.end++; - escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL)); + escape_write_byte(parser, buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL)); return; } } @@ -7556,20 +7708,20 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t flags) { } parser->current.end++; - escape_write_byte(buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META)); + escape_write_byte(parser, buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META)); return; } case '\r': { if (peek_offset(parser, 1) == '\n') { parser->current.end += 2; - pm_buffer_append_byte(buffer, '\n'); + escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags)); return; } } /* fallthrough */ default: { if (parser->current.end < parser->end) { - pm_buffer_append_byte(buffer, *parser->current.end++); + escape_write_byte_encoded(parser, buffer, *parser->current.end++); } return; } @@ -7632,13 +7784,12 @@ lex_question_mark(pm_parser_t *parser) { return PM_TOKEN_CHARACTER_LITERAL; } else { - size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end); + size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end); - // Ternary operators can have a ? immediately followed by an identifier which starts with - // an underscore. We check for this case + // Ternary operators can have a ? immediately followed by an identifier + // which starts with an underscore. We check for this case here. if ( - !(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) || - peek(parser) == '_') || + !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) == '_') || ( (parser->current.end + encoding_width >= parser->end) || !char_is_identifier(parser, parser->current.end + encoding_width) @@ -7704,8 +7855,7 @@ parser_comment(pm_parser_t *parser, pm_comment_type_t type) { *comment = (pm_comment_t) { .type = type, - .start = parser->current.start, - .end = parser->current.end + .location = { parser->current.start, parser->current.end } }; return comment; @@ -7756,7 +7906,7 @@ lex_embdoc(pm_parser_t *parser) { parser->current.type = PM_TOKEN_EMBDOC_END; parser_lex_callback(parser); - comment->end = parser->current.end; + comment->location.end = parser->current.end; pm_list_append(&parser->comment_list, (pm_list_node_t *) comment); return PM_TOKEN_EMBDOC_END; @@ -7779,7 +7929,7 @@ lex_embdoc(pm_parser_t *parser) { pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM); - comment->end = parser->current.end; + comment->location.end = parser->current.end; pm_list_append(&parser->comment_list, (pm_list_node_t *) comment); return PM_TOKEN_EOF; @@ -8487,6 +8637,7 @@ parser_lex(pm_parser_t *parser) { // TODO: handle unterminated heredoc } + parser->explicit_encoding = NULL; lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_HEREDOC, .as.heredoc = { @@ -8507,7 +8658,7 @@ parser_lex(pm_parser_t *parser) { // this is not a valid heredoc declaration. In this case we // will add an error, but we will still return a heredoc // start. - pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM); + pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM); body_start = parser->end; } else { // Otherwise, we want to indicate that the body of the @@ -8893,7 +9044,7 @@ parser_lex(pm_parser_t *parser) { (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) == 's')) || lex_state_spcarg_p(parser, space_seen) ) { - if (!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end)) { + if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) { if (*parser->current.end >= 0x80) { pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT); } @@ -8916,7 +9067,7 @@ parser_lex(pm_parser_t *parser) { // Delimiters for %-literals cannot be alphanumeric. We // validate that here. uint8_t delimiter = peek_offset(parser, 1); - if (delimiter >= 0x80 || parser->encoding.alnum_char(&delimiter, 1)) { + if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) { pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT); goto lex_next_token; } @@ -9442,7 +9593,9 @@ parser_lex(pm_parser_t *parser) { case '\r': parser->current.end++; if (peek(parser) != '\n') { - pm_token_buffer_push(&token_buffer, '\\'); + if (lex_mode->as.regexp.terminator != '\r') { + pm_token_buffer_push(&token_buffer, '\\'); + } pm_token_buffer_push(&token_buffer, '\r'); break; } @@ -9470,7 +9623,20 @@ parser_lex(pm_parser_t *parser) { escape_read(parser, &token_buffer.buffer, PM_ESCAPE_FLAG_REGEXP); break; default: - if (lex_mode->as.regexp.terminator == '/' && peeked == '/') { + if (lex_mode->as.regexp.terminator == peeked) { + // Some characters when they are used as the + // terminator also receive an escape. They are + // enumerated here. + switch (peeked) { + case '$': case ')': case '*': case '+': + case '.': case '>': case '?': case ']': + case '^': case '|': case '}': + pm_token_buffer_push(&token_buffer, '\\'); + break; + default: + break; + } + pm_token_buffer_push(&token_buffer, peeked); parser->current.end++; break; @@ -9745,15 +9911,22 @@ parser_lex(pm_parser_t *parser) { parser->next_start = NULL; } - // We'll check if we're at the end of the file. If we are, then we need to - // return the EOF token. + // Now let's grab the information about the identifier off of the + // current lex mode. + pm_lex_mode_t *lex_mode = parser->lex_modes.current; + + // We'll check if we're at the end of the file. If we are, then we + // will add an error (because we weren't able to find the + // terminator) but still continue parsing so that content after the + // declaration of the heredoc can be parsed. if (parser->current.end >= parser->end) { - LEX(PM_TOKEN_EOF); + pm_parser_err_current(parser, PM_ERR_HEREDOC_TERM); + parser->next_start = lex_mode->as.heredoc.next_start; + parser->heredoc_end = parser->current.end; + lex_state_set(parser, PM_LEX_STATE_END); + LEX(PM_TOKEN_HEREDOC_END); } - // Now let's grab the information about the identifier off of the current - // lex mode. - pm_lex_mode_t *lex_mode = parser->lex_modes.current; const uint8_t *ident_start = lex_mode->as.heredoc.ident_start; size_t ident_length = lex_mode->as.heredoc.ident_length; @@ -9762,7 +9935,6 @@ parser_lex(pm_parser_t *parser) { if (current_token_starts_line(parser)) { const uint8_t *start = parser->current.start; if (start + ident_length <= parser->end) { - bool at_end = false; const uint8_t *newline = next_newline(start, parser->end - start); const uint8_t *ident_end = newline; const uint8_t *terminator_end = newline; @@ -9770,7 +9942,6 @@ parser_lex(pm_parser_t *parser) { if (newline == NULL) { terminator_end = parser->end; ident_end = parser->end; - at_end = true; } else { terminator_end++; if (newline[-1] == '\r') { @@ -9797,6 +9968,7 @@ parser_lex(pm_parser_t *parser) { if (newline != NULL) { pm_newline_list_append(&parser->newline_list, newline); } + parser->current.end = terminator_end; if (*lex_mode->as.heredoc.next_start == '\\') { parser->next_start = NULL; @@ -9805,14 +9977,11 @@ parser_lex(pm_parser_t *parser) { parser->heredoc_end = parser->current.end; } - parser->current_string_common_whitespace = parser->lex_modes.current->as.heredoc.common_whitespace; - lex_mode_pop(parser); - if (!at_end) { - lex_state_set(parser, PM_LEX_STATE_END); - } + lex_state_set(parser, PM_LEX_STATE_END); LEX(PM_TOKEN_HEREDOC_END); } } + size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.indent); if ( lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE && @@ -10043,32 +10212,33 @@ parser_lex(pm_parser_t *parser) { * specify their associativity by adding or subtracting one. */ typedef enum { - PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator - PM_BINDING_POWER_STATEMENT = 2, - PM_BINDING_POWER_MODIFIER = 4, // if unless until while - PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue - PM_BINDING_POWER_COMPOSITION = 8, // and or - PM_BINDING_POWER_NOT = 10, // not - PM_BINDING_POWER_MATCH = 12, // => in - PM_BINDING_POWER_DEFINED = 14, // defined? - PM_BINDING_POWER_ASSIGNMENT = 16, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **= - PM_BINDING_POWER_TERNARY = 18, // ?: - PM_BINDING_POWER_RANGE = 20, // .. ... - PM_BINDING_POWER_LOGICAL_OR = 22, // || - PM_BINDING_POWER_LOGICAL_AND = 24, // && - PM_BINDING_POWER_EQUALITY = 26, // <=> == === != =~ !~ - PM_BINDING_POWER_COMPARISON = 28, // > >= < <= - PM_BINDING_POWER_BITWISE_OR = 30, // | ^ - PM_BINDING_POWER_BITWISE_AND = 32, // & - PM_BINDING_POWER_SHIFT = 34, // << >> - PM_BINDING_POWER_TERM = 36, // + - - PM_BINDING_POWER_FACTOR = 38, // * / % - PM_BINDING_POWER_UMINUS = 40, // -@ - PM_BINDING_POWER_EXPONENT = 42, // ** - PM_BINDING_POWER_UNARY = 44, // ! ~ +@ - PM_BINDING_POWER_INDEX = 46, // [] []= - PM_BINDING_POWER_CALL = 48, // :: . - PM_BINDING_POWER_MAX = 50 + PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator + PM_BINDING_POWER_STATEMENT = 2, + PM_BINDING_POWER_MODIFIER = 4, // if unless until while + PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue + PM_BINDING_POWER_COMPOSITION = 8, // and or + PM_BINDING_POWER_NOT = 10, // not + PM_BINDING_POWER_MATCH = 12, // => in + PM_BINDING_POWER_DEFINED = 14, // defined? + PM_BINDING_POWER_MULTI_ASSIGNMENT = 16, // = + PM_BINDING_POWER_ASSIGNMENT = 18, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **= + PM_BINDING_POWER_TERNARY = 20, // ?: + PM_BINDING_POWER_RANGE = 22, // .. ... + PM_BINDING_POWER_LOGICAL_OR = 24, // || + PM_BINDING_POWER_LOGICAL_AND = 26, // && + PM_BINDING_POWER_EQUALITY = 28, // <=> == === != =~ !~ + PM_BINDING_POWER_COMPARISON = 30, // > >= < <= + PM_BINDING_POWER_BITWISE_OR = 32, // | ^ + PM_BINDING_POWER_BITWISE_AND = 34, // & + PM_BINDING_POWER_SHIFT = 36, // << >> + PM_BINDING_POWER_TERM = 38, // + - + PM_BINDING_POWER_FACTOR = 40, // * / % + PM_BINDING_POWER_UMINUS = 42, // -@ + PM_BINDING_POWER_EXPONENT = 44, // ** + PM_BINDING_POWER_UNARY = 46, // ! ~ +@ + PM_BINDING_POWER_INDEX = 48, // [] []= + PM_BINDING_POWER_CALL = 50, // :: . + PM_BINDING_POWER_MAX = 52 } pm_binding_power_t; /** @@ -10095,7 +10265,7 @@ typedef struct { #define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false } #define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false } #define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false } -#define NON_ASSOCIATIVE(precedence) { precedence + 1, precedence + 1, true, true } +#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true } #define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false } pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = { @@ -10148,12 +10318,12 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = { [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND), // != !~ == === =~ <=> - [PM_TOKEN_BANG_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), - [PM_TOKEN_BANG_TILDE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), - [PM_TOKEN_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), - [PM_TOKEN_EQUAL_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), - [PM_TOKEN_EQUAL_TILDE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), - [PM_TOKEN_LESS_EQUAL_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), + [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY), // > >= < <= [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON), @@ -10366,14 +10536,14 @@ expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_to } static pm_node_t * -parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id); +parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id); /** * This is a wrapper of parse_expression, which also checks whether the resulting node is value expression. */ static pm_node_t * -parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { - pm_node_t *node = parse_expression(parser, binding_power, diag_id); +parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { + pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, diag_id); pm_assert_value_expression(parser, node); return node; } @@ -10458,14 +10628,14 @@ token_begins_expression_p(pm_token_type_t type) { * prefixed by the * operator. */ static pm_node_t * -parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { +parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { if (accept1(parser, PM_TOKEN_USTAR)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + pm_node_t *expression = parse_value_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); return (pm_node_t *) pm_splat_node_create(parser, &operator, expression); } - return parse_value_expression(parser, binding_power, diag_id); + return parse_value_expression(parser, binding_power, accepts_command_call, diag_id); } /** @@ -10583,25 +10753,17 @@ parse_target(pm_parser_t *parser, pm_node_t *target) { return target; } - if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { + if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { parse_write_name(parser, &call->name); - return (pm_node_t *) call; + return (pm_node_t *) pm_call_target_node_create(parser, call); } } // If there is no call operator and the message is "[]" then this is // an aref expression, and we can transform it into an aset // expression. - if ( - (call->call_operator_loc.start == NULL) && - (call->message_loc.start != NULL) && - (call->message_loc.start[0] == '[') && - (call->message_loc.end[-1] == ']') && - (call->block == NULL) - ) { - // Replace the name with "[]=". - call->name = pm_parser_constant_id_constant(parser, "[]=", 3); - return target; + if (pm_call_node_index_p(call)) { + return (pm_node_t *) pm_index_target_node_create(parser, call); } } /* fallthrough */ @@ -10641,6 +10803,7 @@ static pm_node_t * parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_node_t *value) { switch (PM_NODE_TYPE(target)) { case PM_MISSING_NODE: + pm_node_destroy(parser, value); return target; case PM_CLASS_VARIABLE_READ_NODE: { pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target, operator, value); @@ -10651,6 +10814,9 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod return (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value); case PM_CONSTANT_READ_NODE: { pm_constant_write_node_t *node = pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value); + if (context_def_p(parser)) { + pm_parser_err_node(parser, (pm_node_t *) node, PM_ERR_WRITE_TARGET_IN_METHOD); + } pm_node_destroy(parser, target); return (pm_node_t *) node; } @@ -10730,7 +10896,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod return target; } - if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { + if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { // When we get here, we have a method call, because it was // previously marked as a method call but now we have an =. This // looks like: @@ -10748,6 +10914,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod call->base.location.end = arguments->base.location.end; parse_write_name(parser, &call->name); + pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE); return (pm_node_t *) call; } } @@ -10765,6 +10932,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod // Replace the name with "[]=". call->name = pm_parser_constant_id_constant(parser, "[]=", 3); + pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE); return target; } @@ -10815,7 +10983,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); name = parse_target(parser, name); } @@ -10823,7 +10991,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b pm_multi_target_node_targets_append(parser, result, splat); has_rest = true; } else if (token_begins_expression_p(parser->current.type)) { - pm_node_t *target = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + pm_node_t *target = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); target = parse_target(parser, target); pm_multi_target_node_targets_append(parser, result, target); @@ -10874,7 +11042,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context) { context_push(parser, context); while (true) { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); pm_statements_node_body_append(statements, node); // If we're recovering from a syntax error, then we need to stop parsing the @@ -10945,7 +11113,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) { pm_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); + value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } else if (pm_parser_local_depth(parser, &operator) == -1) { pm_parser_err_token(parser, &operator, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } @@ -10963,9 +11131,9 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) { pm_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_EXPRESSION_AFTER_LABEL); + value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL); } else { - if (parser->encoding.isupper_char(label.start, (label.end - 1) - label.start)) { + if (parser->encoding->isupper_char(label.start, (label.end - 1) - label.start)) { pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 }; value = (pm_node_t *) pm_constant_read_node_create(parser, &constant); } else { @@ -10987,7 +11155,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) { break; } default: { - pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_KEY); + pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_KEY); pm_token_t operator; if (pm_symbol_node_label_p(key)) { @@ -10997,7 +11165,7 @@ parse_assocs(pm_parser_t *parser, pm_node_t *node) { operator = parser->previous; } - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value); break; } @@ -11080,15 +11248,11 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser); argument = (pm_node_t *) hash; - bool contains_keyword_splat = false; - if (!match7(parser, terminator, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) { - contains_keyword_splat = parse_assocs(parser, (pm_node_t *) hash); - } - + bool contains_keyword_splat = parse_assocs(parser, (pm_node_t *) hash); parsed_bare_hash = true; parse_arguments_append(parser, arguments, argument); if (contains_keyword_splat) { - arguments->arguments->base.flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT; + pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT); } break; } @@ -11098,7 +11262,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_node_t *expression = NULL; if (token_begins_expression_p(parser->current.type)) { - expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT); + expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_ARGUMENT); } else { if (pm_parser_local_depth(parser, &operator) == -1) { // A block forwarding in a method having `...` parameter (e.g. `def foo(...); bar(&); end`) is available. @@ -11130,7 +11294,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL); } else { - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT); if (parsed_bare_hash) { pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT); @@ -11150,7 +11314,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for // If the token begins an expression then this ... was not actually // argument forwarding but was instead a range. pm_token_t operator = parser->previous; - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right); } else { if (pm_parser_local_depth(parser, &parser->previous) == -1) { @@ -11162,6 +11326,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous); parse_arguments_append(parser, arguments, argument); + arguments->has_forwarding = true; parsed_forwarding_arguments = true; break; } @@ -11170,7 +11335,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for /* fallthrough */ default: { if (argument == NULL) { - argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_ARGUMENT); + argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, PM_ERR_EXPECT_ARGUMENT); } bool contains_keyword_splat = false; @@ -11189,7 +11354,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser); // Finish parsing the one we are part way through - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value); pm_keyword_hash_node_elements_append(bare_hash, argument); @@ -11204,11 +11369,14 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for } parsed_bare_hash = true; + } else if (accept1(parser, PM_TOKEN_KEYWORD_IN)) { + // TODO: Could we solve this with binding powers instead? + pm_parser_err_current(parser, PM_ERR_ARGUMENT_IN); } parse_arguments_append(parser, arguments, argument); if (contains_keyword_splat) { - arguments->arguments->base.flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT; + pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT); } break; } @@ -11500,7 +11668,7 @@ parse_parameters( context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); pm_constant_id_t old_param_name = parser->current_param_name; parser->current_param_name = pm_parser_constant_id_token(parser, &name); - pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT); + pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT); pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value); pm_parameters_node_optionals_append(params, param); @@ -11563,7 +11731,7 @@ parse_parameters( context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); pm_constant_id_t old_param_name = parser->current_param_name; parser->current_param_name = pm_parser_constant_id_token(parser, &local); - pm_node_t *value = parse_value_expression(parser, binding_power, PM_ERR_PARAMETER_NO_DEFAULT_KW); + pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT_KW); parser->current_param_name = old_param_name; context_pop(parser); param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value); @@ -11711,7 +11879,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) { parser_lex(parser); pm_rescue_node_operator_set(rescue, &parser->previous); - pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE); + pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); pm_rescue_node_reference_set(rescue, reference); @@ -11729,7 +11897,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) { // we'll attempt to parse it here and any others delimited by commas. do { - pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_RESCUE_EXPRESSION); + pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION); pm_rescue_node_exceptions_append(rescue, expression); // If we hit a newline, then this is the end of the rescue expression. We @@ -11741,7 +11909,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) { if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) { pm_rescue_node_operator_set(rescue, &parser->previous); - pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_RESCUE_VARIABLE); + pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); pm_rescue_node_reference_set(rescue, reference); @@ -11919,6 +12087,12 @@ parse_block(pm_parser_t *parser) { pm_block_parameters_node_closing_set(block_parameters, &parser->previous); } + uint32_t locals_body_index = 0; + + if (block_parameters) { + locals_body_index = (uint32_t) parser->current_scope->locals.size; + } + accept1(parser, PM_TOKEN_NEWLINE); pm_node_t *statements = NULL; @@ -11950,12 +12124,13 @@ parse_block(pm_parser_t *parser) { if (parameters == NULL && (maximum > 0)) { parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = opening.start, .end = parser->previous.end }, maximum); + locals_body_index = maximum; } pm_constant_id_list_t locals = parser->current_scope->locals; pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); - return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous); + return pm_block_node_create(parser, &locals, locals_body_index, &opening, parameters, statements, &parser->previous); } /** @@ -11964,7 +12139,7 @@ parse_block(pm_parser_t *parser) { * arguments, or blocks). */ static bool -parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block) { +parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call) { bool found = false; if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { @@ -11981,7 +12156,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); } - } else if ((token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) { + } else if (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) { found |= true; pm_accepts_block_stack_push(parser, false); @@ -12016,14 +12191,22 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept } if (block != NULL) { - if (arguments->block == NULL) { + if (arguments->block == NULL && !arguments->has_forwarding) { arguments->block = (pm_node_t *) block; } else { - pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI); - if (arguments->arguments == NULL) { - arguments->arguments = pm_arguments_node_create(parser); + if (arguments->has_forwarding) { + if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) { + pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_FORWARDING); + } + } else { + pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI); + } + if (arguments->block != NULL) { + if (arguments->arguments == NULL) { + arguments->arguments = pm_arguments_node_create(parser); + } + pm_arguments_node_arguments_append(arguments->arguments, arguments->block); } - pm_arguments_node_arguments_append(arguments->arguments, arguments->block); arguments->block = (pm_node_t *) block; } } @@ -12036,7 +12219,7 @@ static inline pm_node_t * parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword) { context_push(parser, PM_CONTEXT_PREDICATE); pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE; - pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, error_id); // Predicates are closed by a term, a "then", or a term and then a "then". bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -12231,6 +12414,26 @@ parse_conditional(pm_parser_t *parser, pm_context_t context) { case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \ case PM_NUMBERED_REFERENCE_READ_NODE +// Assert here that the flags are the same so that we can safely switch the type +// of the node without having to move the flags. +PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING), "Expected the flags to match."); + +/** + * If the encoding was explicitly set through the lexing process, then we need + * to potentially mark the string's flags to indicate how to encode it. + */ +static inline pm_node_flags_t +parse_unescaped_encoding(const pm_parser_t *parser) { + if (parser->explicit_encoding != NULL) { + if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) { + return PM_STRING_FLAGS_FORCED_UTF8_ENCODING; + } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) { + return PM_STRING_FLAGS_FORCED_BINARY_ENCODING; + } + } + return 0; +} + /** * Parse a node that is part of a string. If the subsequent tokens cannot be * parsed as a string part, then NULL is returned. @@ -12247,7 +12450,9 @@ parse_string_part(pm_parser_t *parser) { case PM_TOKEN_STRING_CONTENT: { pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); + pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing); + pm_node_flag_set(node, parse_unescaped_encoding(parser)); parser_lex(parser); return node; @@ -12432,6 +12637,34 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s content = parser->current; unescaped = parser->current_string; parser_lex(parser); + + // If we have two string contents in a row, then the content of this + // symbol is split because of heredoc contents. This looks like: + // + // <current, &bounds, &parser->current_string); + pm_node_list_append(&parts, part); + + if (next_state != PM_LEX_STATE_NONE) { + lex_state_set(parser, next_state); + } + + parser_lex(parser); + expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC); + return (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + } } else { content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end }; pm_string_shared_init(&unescaped, content.start, content.end); @@ -12542,6 +12775,65 @@ outer_scope_using_numbered_parameters_p(pm_parser_t *parser) { return false; } +/** + * Parse an identifier into either a local variable read. If the local variable + * is not found, it returns NULL instead. + */ +static pm_local_variable_read_node_t * +parse_variable(pm_parser_t *parser) { + int depth; + if ((depth = pm_parser_local_depth(parser, &parser->previous)) != -1) { + return pm_local_variable_read_node_create(parser, &parser->previous, (uint32_t) depth); + } + + if (!parser->current_scope->closed && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { + // Now that we know we have a numbered parameter, we need to check + // if it's allowed in this context. If it is, then we will create a + // local variable read. If it's not, then we'll create a normal call + // node but add an error. + if (parser->current_scope->explicit_params) { + pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED); + } else if (outer_scope_using_numbered_parameters_p(parser)) { + pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE); + } else { + // Indicate that this scope is using numbered params so that child + // scopes cannot. + uint8_t number = parser->previous.start[1]; + + // We subtract the value for the character '0' to get the actual + // integer value of the number (only _1 through _9 are valid) + uint8_t numbered_parameters = (uint8_t) (number - '0'); + if (numbered_parameters > parser->current_scope->numbered_parameters) { + parser->current_scope->numbered_parameters = numbered_parameters; + pm_parser_numbered_parameters_set(parser, numbered_parameters); + } + + // When you use a numbered parameter, it implies the existence + // of all of the locals that exist before it. For example, + // referencing _2 means that _1 must exist. Therefore here we + // loop through all of the possibilities and add them into the + // constant pool. + uint8_t current = '1'; + uint8_t *value; + + while (current < number) { + value = malloc(2); + value[0] = '_'; + value[1] = current++; + pm_parser_local_add_owned(parser, value, 2); + } + + // Now we can add the actual token that is being used. For + // this one we can add a shared version since it is directly + // referenced in the source. + pm_parser_local_add_token(parser, &parser->previous); + return pm_local_variable_read_node_create(parser, &parser->previous, 0); + } + } + + return NULL; +} + /** * Parse an identifier into either a local variable read or a call. */ @@ -12550,61 +12842,13 @@ parse_variable_call(pm_parser_t *parser) { pm_node_flags_t flags = 0; if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) { - int depth; - if ((depth = pm_parser_local_depth(parser, &parser->previous)) != -1) { - return (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, (uint32_t) depth); - } - - if (!parser->current_scope->closed && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { - // Now that we know we have a numbered parameter, we need to check - // if it's allowed in this context. If it is, then we will create a - // local variable read. If it's not, then we'll create a normal call - // node but add an error. - if (parser->current_scope->explicit_params) { - pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED); - } else if (outer_scope_using_numbered_parameters_p(parser)) { - pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE); - } else { - // Indicate that this scope is using numbered params so that child - // scopes cannot. - uint8_t number = parser->previous.start[1]; - - // We subtract the value for the character '0' to get the actual - // integer value of the number (only _1 through _9 are valid) - uint8_t numbered_parameters = (uint8_t) (number - '0'); - if (numbered_parameters > parser->current_scope->numbered_parameters) { - parser->current_scope->numbered_parameters = numbered_parameters; - pm_parser_numbered_parameters_set(parser, numbered_parameters); - } - - // When you use a numbered parameter, it implies the existence - // of all of the locals that exist before it. For example, - // referencing _2 means that _1 must exist. Therefore here we - // loop through all of the possibilities and add them into the - // constant pool. - uint8_t current = '1'; - uint8_t *value; - - while (current < number) { - value = malloc(2); - value[0] = '_'; - value[1] = current++; - pm_parser_local_add_owned(parser, value, 2); - } - - // Now we can add the actual token that is being used. For - // this one we can add a shared version since it is directly - // referenced in the source. - pm_parser_local_add_token(parser, &parser->previous); - return (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0); - } - } - + pm_local_variable_read_node_t *node = parse_variable(parser); + if (node != NULL) return (pm_node_t *) node; flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL; } pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous); - node->base.flags |= flags; + pm_node_flag_set((pm_node_t *)node, flags); return (pm_node_t *) node; } @@ -12783,7 +13027,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_node_t *node) { case PM_ARRAY_PATTERN_NODE: { pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner; - if (pattern_node->constant == NULL) { + if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) { pattern_node->base.location.start = node->location.start; pattern_node->base.location.end = closing.end; @@ -12799,7 +13043,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_node_t *node) { case PM_FIND_PATTERN_NODE: { pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner; - if (pattern_node->constant == NULL) { + if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) { pattern_node->base.location.start = node->location.start; pattern_node->base.location.end = closing.end; @@ -12815,7 +13059,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_node_t *node) { case PM_HASH_PATTERN_NODE: { pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner; - if (pattern_node->constant == NULL) { + if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) { pattern_node->base.location.start = node->location.start; pattern_node->base.location.end = closing.end; @@ -12931,10 +13175,15 @@ parse_pattern_hash(pm_parser_t *parser, pm_node_t *first_assoc) { break; } - pm_node_t *assoc; - if (match1(parser, PM_TOKEN_USTAR_STAR)) { - assoc = parse_pattern_keyword_rest(parser); + pm_node_t *assoc = parse_pattern_keyword_rest(parser); + + if (rest == NULL) { + rest = assoc; + } else { + pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST); + pm_node_list_append(&assocs, assoc); + } } else { expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA); pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous); @@ -12948,10 +13197,14 @@ parse_pattern_hash(pm_parser_t *parser, pm_node_t *first_assoc) { } pm_token_t operator = not_provided(parser); - assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value); - } + pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value); - pm_node_list_append(&assocs, assoc); + if (rest != NULL) { + pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST); + } + + pm_node_list_append(&assocs, assoc); + } } pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest); @@ -13062,7 +13315,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { first_assoc = parse_pattern_keyword_rest(parser); break; case PM_TOKEN_STRING_BEGIN: { - pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_HASH_KEY); + pm_node_t *key = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_HASH_KEY); pm_token_t operator = not_provided(parser); if (!pm_symbol_node_label_p(key)) { @@ -13109,7 +13362,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { // expression as the right side of the range. switch (parser->current.type) { case PM_CASE_PRIMITIVE: { - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right); } default: { @@ -13120,7 +13373,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { } } case PM_CASE_PRIMITIVE: { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, diag_id); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, false, diag_id); // Now that we have a primitive, we need to check if it's part of a range. if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) { @@ -13131,7 +13384,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { // node. Otherwise, we'll create an endless range. switch (parser->current.type) { case PM_CASE_PRIMITIVE: { - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (pm_node_t *) pm_range_node_create(parser, node, &operator, right); } default: @@ -13150,7 +13403,11 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { switch (parser->current.type) { case PM_TOKEN_IDENTIFIER: { parser_lex(parser); - pm_node_t *variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0); + pm_node_t *variable = (pm_node_t *) parse_variable(parser); + if (variable == NULL) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE, (int) (parser->previous.end - parser->previous.start), parser->previous.start); + variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0); + } return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable); } @@ -13191,7 +13448,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { pm_token_t lparen = parser->current; parser_lex(parser); - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; accept1(parser, PM_TOKEN_NEWLINE); @@ -13451,13 +13708,15 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { // Here we have found a string literal. We'll parse it and add it to // the list of strings. - assert(parser->lex_modes.current->mode == PM_LEX_STRING); - bool lex_interpolation = parser->lex_modes.current->as.string.interpolation; + const pm_lex_mode_t *lex_mode = parser->lex_modes.current; + assert(lex_mode->mode == PM_LEX_STRING); + bool lex_interpolation = lex_mode->as.string.interpolation; pm_token_t opening = parser->current; parser_lex(parser); - if (accept1(parser, PM_TOKEN_STRING_END)) { + if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { + expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM); // If we get here, then we have an end immediately after a // start. In that case we'll create an empty content token and // return an uninterpolated string. @@ -13520,7 +13779,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_TERM); - node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped); + node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped); } else { expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM); node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped); @@ -13534,9 +13793,10 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { pm_string_t unescaped = parser->current_string; parser_lex(parser); - if (match1(parser, PM_TOKEN_STRING_END)) { + if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped); - parser_lex(parser); + pm_node_flag_set(node, parse_unescaped_encoding(parser)); + expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM); } else if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped); } else { @@ -13547,6 +13807,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { pm_token_t string_closing = not_provided(parser); pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->previous, &string_closing, &unescaped); + pm_node_flag_set(part, parse_unescaped_encoding(parser)); pm_node_list_append(&parts, part); while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) { @@ -13559,7 +13820,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM); - node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); + node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current); } else { expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM); node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); @@ -13582,7 +13843,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM); - node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); + node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current); } else { expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM); node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); @@ -13630,7 +13891,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { * Parse an expression that begins with the previous node that we just lexed. */ static inline pm_node_t * -parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { +parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call) { switch (parser->current.type) { case PM_TOKEN_BRACKET_LEFT_ARRAY: { parser_lex(parser); @@ -13666,7 +13927,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_parser_err_token(parser, &operator, PM_ERR_ARGUMENT_NO_FORWARDING_STAR); } } else { - expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR); + expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR); } element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression); @@ -13684,7 +13945,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parsed_bare_hash = true; } else { - element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_ARRAY_EXPRESSION); + element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_ARRAY_EXPRESSION); if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { @@ -13700,7 +13961,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { operator = not_provided(parser); } - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value); pm_keyword_hash_node_elements_append(hash, assoc); @@ -13741,7 +14002,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // of statements within the parentheses. pm_accepts_block_stack_push(parser, true); context_push(parser, PM_CONTEXT_PARENS); - pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); context_pop(parser); // Determine if this statement is followed by a terminator. In the @@ -13817,7 +14078,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // Parse each statement within the parentheses. while (true) { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); pm_statements_node_body_append(statements, node); // If we're recovering from a syntax error, then we need to stop @@ -13880,6 +14141,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t closing = not_provided(parser); pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing); + pm_node_flag_set(node, parse_unescaped_encoding(parser)); // Characters can be followed by strings in which case they are // automatically concatenated. @@ -13907,11 +14169,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // fact a method call, not a constant read. if ( match1(parser, PM_TOKEN_PARENTHESIS_LEFT) || - (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) || + (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) || (pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT)) ) { pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments); } @@ -13945,7 +14207,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t operator = parser->current; parser_lex(parser); - pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right); } case PM_TOKEN_FLOAT: @@ -14004,10 +14266,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_call_node_t *call = (pm_call_node_t *) node; pm_arguments_t arguments = { 0 }; - if (parse_arguments_list(parser, &arguments, true)) { + if (parse_arguments_list(parser, &arguments, true, accepts_command_call)) { // Since we found arguments, we need to turn off the // variable call bit in the flags. - call->base.flags &= (pm_node_flags_t) ~PM_CALL_NODE_FLAGS_VARIABLE_CALL; + pm_node_flag_unset((pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL); call->opening_loc = arguments.opening_loc; call->arguments = arguments.arguments; @@ -14031,11 +14293,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // can still be a method call if it is followed by arguments or // a block, so we need to check for that here. if ( - (binding_power <= PM_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) || + (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) || (pm_accepts_block_stack_p(parser) && match2(parser, PM_TOKEN_KEYWORD_DO, PM_TOKEN_BRACE_LEFT)) ) { pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments); pm_node_destroy(parser, node); @@ -14066,7 +14328,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) { // If we get here, then we have an empty heredoc. We'll create // an empty content token and return an empty string node. - lex_state_set(parser, PM_LEX_STATE_END); + lex_mode_pop(parser); expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM); pm_token_t content = parse_strings_empty_content(parser->previous.start); @@ -14087,6 +14349,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // content and we're at the end of the heredoc, so we can return // just a string node with the heredoc opening and closing as // its opening and closing. + pm_node_flag_set(part, parse_unescaped_encoding(parser)); pm_string_node_t *cast = (pm_string_node_t *) part; cast->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening); @@ -14098,13 +14361,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { cast->base.type = PM_X_STRING_NODE; } - size_t common_whitespace = parser->current_string_common_whitespace; + size_t common_whitespace = lex_mode->as.heredoc.common_whitespace; if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) { parse_heredoc_dedent_string(&cast->unescaped, common_whitespace); } node = (pm_node_t *) cast; - lex_state_set(parser, PM_LEX_STATE_END); + lex_mode_pop(parser); expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM); } else { // If we get here, then we have multiple parts in the heredoc, @@ -14119,13 +14382,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } } + size_t common_whitespace = lex_mode->as.heredoc.common_whitespace; + // Now that we have all of the parts, create the correct type of // interpolated node. if (quote == PM_HEREDOC_QUOTE_BACKTICK) { pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening); cast->parts = parts; - lex_state_set(parser, PM_LEX_STATE_END); + lex_mode_pop(parser); expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM); pm_interpolated_xstring_node_closing_set(cast, &parser->previous); @@ -14134,7 +14399,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } else { pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening); - lex_state_set(parser, PM_LEX_STATE_END); + lex_mode_pop(parser); expect1(parser, PM_TOKEN_HEREDOC_END, PM_ERR_HEREDOC_TERM); pm_interpolated_string_node_closing_set(cast, &parser->previous); @@ -14144,7 +14409,6 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // If this is a heredoc that is indented with a ~, then we need // to dedent each line by the common leading whitespace. - size_t common_whitespace = parser->current_string_common_whitespace; if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) { pm_node_list_t *nodes; if (quote == PM_HEREDOC_QUOTE_BACKTICK) { @@ -14251,7 +14515,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } else if (!token_begins_expression_p(parser->current.type)) { predicate = NULL; } else { - predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CASE_EXPRESSION_AFTER_CASE); + predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CASE_EXPRESSION_AFTER_CASE); while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)); } @@ -14278,14 +14542,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { do { if (accept1(parser, PM_TOKEN_USTAR)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression); pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node); if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break; } else { - pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CASE_EXPRESSION_AFTER_WHEN); + pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN); pm_when_node_conditions_append(when_node, condition); if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE)) break; @@ -14342,11 +14606,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { // for guard clauses in the form of `if` or `unless` statements. if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) { pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_IF_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, true, PM_ERR_CONDITIONAL_IF_PREDICATE); pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate); } else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) { pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, true, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate); } @@ -14505,7 +14769,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t keyword = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); if ( arguments.opening_loc.start == NULL && @@ -14522,7 +14786,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t keyword = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, false); + parse_arguments_list(parser, &arguments, false, accepts_command_call); return (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc); } @@ -14533,7 +14797,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (accept1(parser, PM_TOKEN_LESS_LESS)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_NOT, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_NOT, true, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS); pm_constant_id_t old_param_name = parser->current_param_name; parser->current_param_name = 0; @@ -14561,7 +14825,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_CLASS_NAME); + pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_CLASS_NAME); pm_token_t name = parser->previous; if (name.type != PM_TOKEN_CONSTANT) { pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME); @@ -14577,7 +14841,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser->command_start = true; parser_lex(parser); - superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CLASS_SUPERCLASS); + superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CLASS_SUPERCLASS); } else { inheritance_operator = not_provided(parser); superclass = NULL; @@ -14737,7 +15001,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t lparen = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_DEF_RECEIVER); expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN); pm_token_t rparen = parser->previous; @@ -14811,6 +15075,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } } + uint32_t locals_body_index = (uint32_t) parser->current_scope->locals.size; + context_pop(parser); pm_node_t *statements = NULL; pm_token_t equal; @@ -14826,11 +15092,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_do_loop_stack_push(parser, false); statements = (pm_node_t *) pm_statements_node_create(parser); - pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, PM_ERR_DEF_ENDLESS); + pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION, PM_ERR_DEF_ENDLESS); if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) { pm_token_t rescue_keyword = parser->previous; - pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *value = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE); pm_rescue_modifier_node_t *rescue_node = pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value); statement = (pm_node_t *)rescue_node; } @@ -14881,6 +15147,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { params, statements, &locals, + locals_body_index, &def_keyword, &operator, &lparen, @@ -14899,18 +15166,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { lparen = parser->previous; - expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_DEFINED_EXPRESSION); + expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_DEFINED_EXPRESSION); if (parser->recovering) { rparen = not_provided(parser); } else { + accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN); rparen = parser->previous; } } else { lparen = not_provided(parser); rparen = not_provided(parser); - expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_DEFINED_EXPRESSION); + expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_DEFINED_EXPRESSION); } return (pm_node_t *) pm_defined_node_create( @@ -14956,12 +15224,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); } index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name); } else if (token_begins_expression_p(parser->current.type)) { - index = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + index = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); } else { pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX); index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.start, for_keyword.end); @@ -14980,7 +15248,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN); pm_token_t in_keyword = parser->previous; - pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_FOR_COLLECTION); + pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_FOR_COLLECTION); pm_do_loop_stack_pop(parser); pm_token_t do_keyword; @@ -15048,7 +15316,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); } else { - receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_NOT_EXPRESSION); + receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_NOT_EXPRESSION); pm_conditional_predicate(receiver); if (!parser->recovering) { @@ -15058,7 +15326,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } } } else { - receiver = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_NOT_EXPRESSION); + receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, PM_ERR_NOT_EXPRESSION); pm_conditional_predicate(receiver); } @@ -15071,7 +15339,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t module_keyword = parser->previous; - pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_MODULE_NAME); + pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_MODULE_NAME); pm_token_t name; // If we can recover from a syntax error that occurred while parsing @@ -15147,7 +15415,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); pm_do_loop_stack_pop(parser); expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); @@ -15168,7 +15436,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE); pm_do_loop_stack_pop(parser); expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE); @@ -15397,8 +15665,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } else { expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM); } - pm_array_node_close_set(array, &closing); + pm_array_node_close_set(array, &closing); return (pm_node_t *) array; } case PM_TOKEN_PERCENT_UPPER_W: { @@ -15406,19 +15674,24 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t opening = parser->previous; pm_array_node_t *array = pm_array_node_create(parser, &opening); - // This is the current node that we are parsing that will be added to the - // list of elements. + // This is the current node that we are parsing that will be added + // to the list of elements. pm_node_t *current = NULL; while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { switch (parser->current.type) { case PM_TOKEN_WORDS_SEP: { + // Reset the explicit encoding if we hit a separator + // since each element can have its own encoding. + parser->explicit_encoding = NULL; + if (current == NULL) { - // If we hit a separator before we have any content, then we don't - // need to do anything. + // If we hit a separator before we have any content, + // then we don't need to do anything. } else { - // If we hit a separator after we've hit content, then we need to - // append that content to the list and reset the current node. + // If we hit a separator after we've hit content, + // then we need to append that content to the list + // and reset the current node. pm_array_node_elements_append(array, current); current = NULL; } @@ -15431,22 +15704,25 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t closing = not_provided(parser); pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing); + pm_node_flag_set(string, parse_unescaped_encoding(parser)); parser_lex(parser); if (current == NULL) { - // If we hit content and the current node is NULL, then this is - // the first string content we've seen. In that case we're going - // to create a new string node and set that to the current. + // If we hit content and the current node is NULL, + // then this is the first string content we've seen. + // In that case we're going to create a new string + // node and set that to the current. current = string; } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) { - // If we hit string content and the current node is an - // interpolated string, then we need to append the string content - // to the list of child nodes. + // If we hit string content and the current node is + // an interpolated string, then we need to append + // the string content to the list of child nodes. pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, string); } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) { - // If we hit string content and the current node is a string node, - // then we need to convert the current node into an interpolated - // string and add the string content to the list of child nodes. + // If we hit string content and the current node is + // a string node, then we need to convert the + // current node into an interpolated string and add + // the string content to the list of child nodes. pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); pm_interpolated_string_node_append(interpolated, current); pm_interpolated_string_node_append(interpolated, string); @@ -15459,24 +15735,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } case PM_TOKEN_EMBVAR: { if (current == NULL) { - // If we hit an embedded variable and the current node is NULL, - // then this is the start of a new string. We'll set the current - // node to a new interpolated string. + // If we hit an embedded variable and the current + // node is NULL, then this is the start of a new + // string. We'll set the current node to a new + // interpolated string. pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing); } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) { - // If we hit an embedded variable and the current node is a string - // node, then we'll convert the current into an interpolated - // string and add the string node to the list of parts. + // If we hit an embedded variable and the current + // node is a string node, then we'll convert the + // current into an interpolated string and add the + // string node to the list of parts. pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); pm_interpolated_string_node_append(interpolated, current); current = (pm_node_t *) interpolated; } else { - // If we hit an embedded variable and the current node is an - // interpolated string, then we'll just add the embedded variable. + // If we hit an embedded variable and the current + // node is an interpolated string, then we'll just + // add the embedded variable. } pm_node_t *part = parse_string_part(parser); @@ -15485,25 +15764,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } case PM_TOKEN_EMBEXPR_BEGIN: { if (current == NULL) { - // If we hit an embedded expression and the current node is NULL, - // then this is the start of a new string. We'll set the current - // node to a new interpolated string. + // If we hit an embedded expression and the current + // node is NULL, then this is the start of a new + // string. We'll set the current node to a new + // interpolated string. pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing); } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) { - // If we hit an embedded expression and the current node is a - // string node, then we'll convert the current into an - // interpolated string and add the string node to the list of - // parts. + // If we hit an embedded expression and the current + // node is a string node, then we'll convert the + // current into an interpolated string and add the + // string node to the list of parts. pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing); pm_interpolated_string_node_append(interpolated, current); current = (pm_node_t *) interpolated; } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) { - // If we hit an embedded expression and the current node is an - // interpolated string, then we'll just continue on. + // If we hit an embedded expression and the current + // node is an interpolated string, then we'll just + // continue on. } else { assert(false && "unreachable"); } @@ -15531,8 +15812,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } else { expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM); } - pm_array_node_close_set(array, &closing); + pm_array_node_close_set(array, &closing); return (pm_node_t *) array; } case PM_TOKEN_REGEXP_BEGIN: { @@ -15640,8 +15921,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t content = parser->current; parser_lex(parser); - if (accept1(parser, PM_TOKEN_STRING_END)) { - return (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped); + if (match1(parser, PM_TOKEN_STRING_END)) { + pm_node_t *node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped); + pm_node_flag_set(node, parse_unescaped_encoding(parser)); + parser_lex(parser); + return node; } // If we get here, then we have interpolation so we'll need to @@ -15650,7 +15934,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_token_t opening = not_provided(parser); pm_token_t closing = not_provided(parser); + pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped); + pm_node_flag_set(part, parse_unescaped_encoding(parser)); pm_interpolated_xstring_node_append(node, part); } else { @@ -15692,7 +15978,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); } pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name); @@ -15707,7 +15993,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_BANG); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, PM_ERR_UNARY_RECEIVER_BANG); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!"); pm_conditional_predicate(receiver); @@ -15717,7 +16003,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_TILDE); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_TILDE); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~"); return (pm_node_t *) node; @@ -15726,7 +16012,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_MINUS); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@"); return (pm_node_t *) node; @@ -15735,11 +16021,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_MINUS); + pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_MINUS); if (accept1(parser, PM_TOKEN_STAR_STAR)) { pm_token_t exponent_operator = parser->previous; - pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, PM_ERR_EXPECT_ARGUMENT); + pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, false, PM_ERR_EXPECT_ARGUMENT); node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent); node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@"); } else { @@ -15801,6 +16087,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } } + uint32_t locals_body_index = 0; + + if (block_parameters) { + locals_body_index = (uint32_t) parser->current_scope->locals.size; + } + pm_token_t opening; pm_node_t *body = NULL; parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting; @@ -15835,18 +16127,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { if (parameters == NULL && (maximum > 0)) { parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = operator.start, .end = parser->previous.end }, maximum); + locals_body_index = maximum; } pm_constant_id_list_t locals = parser->current_scope->locals; pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); - return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body); + return (pm_node_t *) pm_lambda_node_create(parser, &locals, locals_body_index, &operator, &opening, &parser->previous, parameters, body); } case PM_TOKEN_UPLUS: { parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, PM_ERR_UNARY_RECEIVER_PLUS); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_PLUS); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@"); return (pm_node_t *) node; @@ -15869,14 +16162,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } static inline pm_node_t * -parse_assignment_value(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { - pm_node_t *value = parse_value_expression(parser, binding_power, diag_id); +parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { + pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id); // Contradicting binding powers, the right-hand-side value of rthe assignment allows the `rescue` modifier. if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) { pm_token_t rescue = parser->current; parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE); return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right); } @@ -15886,8 +16179,8 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t binding_power, pm static inline pm_node_t * -parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { - pm_node_t *value = parse_starred_expression(parser, binding_power, diag_id); +parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { + pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id); bool is_single_value = true; if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) { @@ -15899,7 +16192,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding value = (pm_node_t *) array; while (accept1(parser, PM_TOKEN_COMMA)) { - pm_node_t *element = parse_starred_expression(parser, binding_power, PM_ERR_ARRAY_ELEMENT); + pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT); pm_array_node_elements_append(array, element); if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break; } @@ -15909,7 +16202,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding if (is_single_value && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) { pm_token_t rescue = parser->current; parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE); return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right); } @@ -15967,7 +16260,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t * pm_string_list_t named_captures = { 0 }; pm_node_t *result; - if (pm_regexp_named_capture_group_names(pm_string_source(content), pm_string_length(content), &named_captures, parser->encoding_changed, &parser->encoding) && (named_captures.length > 0)) { + if (pm_regexp_named_capture_group_names(pm_string_source(content), pm_string_length(content), &named_captures, parser->encoding_changed, parser->encoding) && (named_captures.length > 0)) { // Since we should not create a MatchWriteNode when all capture names // are invalid, creating a MatchWriteNode is delayed here. pm_match_write_node_t *match = NULL; @@ -16001,6 +16294,8 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t * if (memory == NULL) abort(); memcpy(memory, source, length); + // This silences clang analyzer warning about leak of memory pointed by `memory`. + // NOLINTNEXTLINE(clang-analyzer-*) name = pm_parser_constant_id_owned(parser, (const uint8_t *) memory, length); if (pm_token_is_numbered_parameter(source, source + length)) { @@ -16048,7 +16343,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t * } static inline pm_node_t * -parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power) { +parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call) { pm_token_t token = parser->current; switch (token.type) { @@ -16067,7 +16362,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t /* fallthrough */ case PM_CASE_WRITABLE: { parser_lex(parser); - pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); + pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, node, &token, value); } case PM_SPLAT_NODE: { @@ -16075,7 +16370,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_multi_target_node_targets_append(parser, multi_target, node); parser_lex(parser); - pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); + pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, (pm_node_t *) multi_target, &token, value); } default: @@ -16097,7 +16392,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -16106,7 +16401,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16115,13 +16410,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); } case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16130,7 +16425,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16140,7 +16435,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -16158,7 +16453,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end); pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -16169,7 +16464,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (pm_call_node_index_p(cast)) { - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value); } @@ -16181,7 +16476,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -16208,7 +16503,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -16217,7 +16512,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16226,13 +16521,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); } case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16241,7 +16536,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16251,7 +16546,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -16269,7 +16564,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end); pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -16280,7 +16575,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (pm_call_node_index_p(cast)) { - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value); } @@ -16292,7 +16587,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -16329,7 +16624,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -16338,7 +16633,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16347,13 +16642,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); } case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16362,7 +16657,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -16372,7 +16667,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -16390,7 +16685,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end); pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -16401,7 +16696,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (pm_call_node_index_p(cast)) { - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value); } @@ -16413,7 +16708,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -16435,14 +16730,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_KEYWORD_AND: { parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_AND, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_and_node_create(parser, node, &token, right); } case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_PIPE_PIPE: { parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_OR, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_or_node_create(parser, node, &token, right); } case PM_TOKEN_EQUAL_TILDE: { @@ -16454,7 +16749,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // // In this case, `foo` should be a method call and not a local yet. parser_lex(parser); - pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *argument = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); // By default, we're going to create a call node and then return it. pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument); @@ -16539,7 +16834,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_STAR_STAR: { parser_lex(parser); - pm_node_t *argument = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *argument = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument); } case PM_TOKEN_AMPERSAND_DOT: @@ -16550,7 +16845,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // This if statement handles the foo.() syntax. if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, false); return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments); } @@ -16572,7 +16867,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } } - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); pm_call_node_t *call = pm_call_node_call_create(parser, node, &operator, &message, &arguments); if ( @@ -16592,7 +16887,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_node_t *right = NULL; if (token_begins_expression_p(parser->current.type)) { - right = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + right = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); } return (pm_node_t *) pm_range_node_create(parser, node, &token, right); @@ -16601,14 +16896,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_IF_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_IF_PREDICATE); return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: { pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: { @@ -16616,7 +16911,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(statements, node); - pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_KEYWORD_WHILE_MODIFIER: { @@ -16624,13 +16919,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(statements, node); - pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE); return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_QUESTION_MARK: { pm_token_t qmark = parser->current; parser_lex(parser); - pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE); + pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_TERNARY_EXPRESSION_TRUE); if (parser->recovering) { // If parsing the true expression of this ternary resulted in a syntax @@ -16649,7 +16944,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON); pm_token_t colon = parser->previous; - pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE); + pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_TERNARY_EXPRESSION_FALSE); return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression); } @@ -16675,7 +16970,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t message = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments); } else { // Otherwise, this is a constant path. That would look like Foo::Bar. @@ -16700,7 +16995,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // If we have an identifier following a '::' operator, then it is for // sure a method call. pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, accepts_command_call); pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments); // If this is followed by a comma then it is a multiple assignment. @@ -16714,7 +17009,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // If we have a parenthesis following a '::' operator, then it is the // method call shorthand. That would look like Foo::(bar). pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true); + parse_arguments_list(parser, &arguments, true, false); return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments); } @@ -16728,7 +17023,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: { parser_lex(parser); accept1(parser, PM_TOKEN_NEWLINE); - pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *value = parse_expression(parser, binding_power, true, PM_ERR_RESCUE_MODIFIER_VALUE); return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value); } @@ -16824,9 +17119,9 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t * determine if they need to perform additional cleanup. */ static pm_node_t * -parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagnostic_id_t diag_id) { +parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { pm_token_t recovery = parser->previous; - pm_node_t *node = parse_expression_prefix(parser, binding_power); + pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call); switch (PM_NODE_TYPE(node)) { case PM_MISSING_NODE: @@ -16867,12 +17162,68 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagn binding_power <= current_binding_powers.left && current_binding_powers.binary ) { - node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right); - if ( - current_binding_powers.nonassoc && - current_binding_powers.right <= pm_binding_powers[parser->current.type].left - ) { - break; + node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call); + if (current_binding_powers.nonassoc) { + bool endless_range_p = PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL; + pm_binding_power_t left = endless_range_p ? PM_BINDING_POWER_TERM : current_binding_powers.left; + if ( + left <= pm_binding_powers[parser->current.type].left || + // Exceptionally to operator precedences, '1.. & 2' is rejected. + // '1.. || 2' is also an exception, but it is handled by the lexer. + // (Here, parser->current is PM_TOKEN_PIPE, not PM_TOKEN_PIPE_PIPE). + (endless_range_p && match1(parser, PM_TOKEN_AMPERSAND)) + ) { + break; + } + } + if (accepts_command_call) { + // A command-style method call is only accepted on method chains. + // Thus, we check whether the parsed node can continue method chains. + // The method chain can continue if the parsed node is one of the following five kinds: + // (1) index access: foo[1] + // (2) attribute access: foo.bar + // (3) method call with parenthesis: foo.bar(1) + // (4) method call with a block: foo.bar do end + // (5) constant path: foo::Bar + switch (node->type) { + case PM_CALL_NODE: { + pm_call_node_t *cast = (pm_call_node_t *)node; + if ( + // (1) foo[1] + !( + cast->call_operator_loc.start == NULL && + cast->message_loc.start != NULL && + cast->message_loc.start[0] == '[' && + cast->message_loc.end[-1] == ']' + ) && + // (2) foo.bar + !( + cast->call_operator_loc.start != NULL && + cast->arguments == NULL && + cast->block == NULL && + cast->opening_loc.start == NULL + ) && + // (3) foo.bar(1) + !( + cast->call_operator_loc.start != NULL && + cast->opening_loc.start != NULL + ) && + // (4) foo.bar do end + !( + cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE) + ) + ) { + accepts_command_call = false; + } + break; + } + // (5) foo::Bar + case PM_CONSTANT_PATH_NODE: + break; + default: + accepts_command_call = false; + break; + } } } @@ -16881,9 +17232,14 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagn static pm_node_t * parse_program(pm_parser_t *parser) { - pm_parser_scope_push(parser, !parser->current_scope); - parser_lex(parser); + // If the current scope is NULL, then we want to push a new top level scope. + // The current scope could exist in the event that we are parsing an eval + // and the user has passed into scopes that already exist. + if (parser->current_scope == NULL) { + pm_parser_scope_push(parser, true); + } + parser_lex(parser); pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN); if (!statements) { statements = pm_statements_node_create(parser); @@ -16936,7 +17292,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm .error_list = { 0 }, .current_scope = NULL, .current_context = NULL, - .encoding = *pm_encoding_utf_8, + .encoding = PM_ENCODING_UTF_8_ENTRY, .encoding_changed_callback = NULL, .encoding_comment_start = source, .lex_callback = NULL, @@ -16946,6 +17302,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm .integer_base = 0, .current_string = PM_STRING_EMPTY, .start_line = 1, + .explicit_encoding = NULL, .command_start = true, .recovering = false, .encoding_changed = false, @@ -17005,6 +17362,9 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm parser->suppress_warnings = true; } + // version option + parser->version = options->version; + // scopes option for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) { const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index); @@ -17172,7 +17532,7 @@ pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t s pm_node_t *node = pm_parse(&parser); pm_serialize_header(buffer); - pm_serialize_encoding(&parser.encoding, buffer); + pm_serialize_encoding(parser.encoding, buffer); pm_buffer_append_varsint(buffer, parser.start_line); pm_serialize_comment_list(&parser, &parser.comment_list, buffer); diff --git a/src/main/c/yarp/src/serialize.c b/src/main/c/yarp/src/serialize.c index 53ad9b933bc8..06f99e3b753a 100644 --- a/src/main/c/yarp/src/serialize.c +++ b/src/main/c/yarp/src/serialize.c @@ -88,21 +88,21 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_ARGUMENTS_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); uint32_t arguments_size = pm_sizet_to_u32(((pm_arguments_node_t *)node)->arguments.size); pm_buffer_append_varuint(buffer, arguments_size); for (uint32_t index = 0; index < arguments_size; index++) { pm_serialize_node(parser, (pm_node_t *) ((pm_arguments_node_t *)node)->arguments.nodes[index], buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_ARRAY_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); uint32_t elements_size = pm_sizet_to_u32(((pm_array_node_t *)node)->elements.size); pm_buffer_append_varuint(buffer, elements_size); for (uint32_t index = 0; index < elements_size; index++) { pm_serialize_node(parser, (pm_node_t *) ((pm_array_node_t *)node)->elements.nodes[index], buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_ARRAY_PATTERN_NODE: { @@ -190,6 +190,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { for (uint32_t index = 0; index < locals_size; index++) { pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_block_node_t *)node)->locals.ids[index])); } + pm_buffer_append_varuint(buffer, ((pm_block_node_t *)node)->locals_body_index); if (((pm_block_node_t *)node)->parameters == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -228,18 +229,19 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_CALL_AND_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_call_and_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { pm_serialize_node(parser, (pm_node_t *)((pm_call_and_write_node_t *)node)->receiver, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_and_write_node_t *)node)->read_name)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_and_write_node_t *)node)->write_name)); pm_serialize_node(parser, (pm_node_t *)((pm_call_and_write_node_t *)node)->value, buffer); break; } case PM_CALL_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_call_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -256,16 +258,15 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_call_node_t *)node)->block, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_CALL_OPERATOR_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_call_operator_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { pm_serialize_node(parser, (pm_node_t *)((pm_call_operator_write_node_t *)node)->receiver, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->read_name)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->write_name)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_operator_write_node_t *)node)->operator)); @@ -273,17 +274,23 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_CALL_OR_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_call_or_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { pm_serialize_node(parser, (pm_node_t *)((pm_call_or_write_node_t *)node)->receiver, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_or_write_node_t *)node)->read_name)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_or_write_node_t *)node)->write_name)); pm_serialize_node(parser, (pm_node_t *)((pm_call_or_write_node_t *)node)->value, buffer); break; } + case PM_CALL_TARGET_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); + pm_serialize_node(parser, (pm_node_t *)((pm_call_target_node_t *)node)->receiver, buffer); + pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_call_target_node_t *)node)->name)); + break; + } case PM_CAPTURE_PATTERN_NODE: { pm_serialize_node(parser, (pm_node_t *)((pm_capture_pattern_node_t *)node)->value, buffer); pm_serialize_node(parser, (pm_node_t *)((pm_capture_pattern_node_t *)node)->target, buffer); @@ -468,6 +475,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { for (uint32_t index = 0; index < locals_size; index++) { pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_def_node_t *)node)->locals.ids[index])); } + pm_buffer_append_varuint(buffer, ((pm_def_node_t *)node)->locals_body_index); // serialize length uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t)); memcpy(buffer->value + length_offset, &length, sizeof(uint32_t)); @@ -524,6 +532,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_FLIP_FLOP_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_flip_flop_node_t *)node)->left == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -534,7 +543,6 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_flip_flop_node_t *)node)->right, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_FLOAT_NODE: { @@ -654,6 +662,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_INDEX_AND_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_index_and_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -669,11 +678,11 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_index_and_write_node_t *)node)->block, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_node(parser, (pm_node_t *)((pm_index_and_write_node_t *)node)->value, buffer); break; } case PM_INDEX_OPERATOR_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_index_operator_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -689,12 +698,12 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_index_operator_write_node_t *)node)->block, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_index_operator_write_node_t *)node)->operator)); pm_serialize_node(parser, (pm_node_t *)((pm_index_operator_write_node_t *)node)->value, buffer); break; } case PM_INDEX_OR_WRITE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_index_or_write_node_t *)node)->receiver == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -710,10 +719,24 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_index_or_write_node_t *)node)->block, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_node(parser, (pm_node_t *)((pm_index_or_write_node_t *)node)->value, buffer); break; } + case PM_INDEX_TARGET_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); + pm_serialize_node(parser, (pm_node_t *)((pm_index_target_node_t *)node)->receiver, buffer); + if (((pm_index_target_node_t *)node)->arguments == NULL) { + pm_buffer_append_byte(buffer, 0); + } else { + pm_serialize_node(parser, (pm_node_t *)((pm_index_target_node_t *)node)->arguments, buffer); + } + if (((pm_index_target_node_t *)node)->block == NULL) { + pm_buffer_append_byte(buffer, 0); + } else { + pm_serialize_node(parser, (pm_node_t *)((pm_index_target_node_t *)node)->block, buffer); + } + break; + } case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: { pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_instance_variable_and_write_node_t *)node)->name)); pm_serialize_node(parser, (pm_node_t *)((pm_instance_variable_and_write_node_t *)node)->value, buffer); @@ -748,21 +771,21 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); uint32_t parts_size = pm_sizet_to_u32(((pm_interpolated_match_last_line_node_t *)node)->parts.size); pm_buffer_append_varuint(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { pm_serialize_node(parser, (pm_node_t *) ((pm_interpolated_match_last_line_node_t *)node)->parts.nodes[index], buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); uint32_t parts_size = pm_sizet_to_u32(((pm_interpolated_regular_expression_node_t *)node)->parts.size); pm_buffer_append_varuint(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { pm_serialize_node(parser, (pm_node_t *) ((pm_interpolated_regular_expression_node_t *)node)->parts.nodes[index], buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_INTERPOLATED_STRING_NODE: { @@ -790,6 +813,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_KEYWORD_HASH_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); uint32_t elements_size = pm_sizet_to_u32(((pm_keyword_hash_node_t *)node)->elements.size); pm_buffer_append_varuint(buffer, elements_size); for (uint32_t index = 0; index < elements_size; index++) { @@ -807,6 +831,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { for (uint32_t index = 0; index < locals_size; index++) { pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_lambda_node_t *)node)->locals.ids[index])); } + pm_buffer_append_varuint(buffer, ((pm_lambda_node_t *)node)->locals_body_index); if (((pm_lambda_node_t *)node)->parameters == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -855,8 +880,8 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_MATCH_LAST_LINE_NODE: { - pm_serialize_string(parser, &((pm_match_last_line_node_t *)node)->unescaped, buffer); pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); + pm_serialize_string(parser, &((pm_match_last_line_node_t *)node)->unescaped, buffer); break; } case PM_MATCH_PREDICATE_NODE: { @@ -1050,6 +1075,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_RANGE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); if (((pm_range_node_t *)node)->left == NULL) { pm_buffer_append_byte(buffer, 0); } else { @@ -1060,7 +1086,6 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { } else { pm_serialize_node(parser, (pm_node_t *)((pm_range_node_t *)node)->right, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_RATIONAL_NODE: { @@ -1071,8 +1096,8 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_REGULAR_EXPRESSION_NODE: { - pm_serialize_string(parser, &((pm_regular_expression_node_t *)node)->unescaped, buffer); pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); + pm_serialize_string(parser, &((pm_regular_expression_node_t *)node)->unescaped, buffer); break; } case PM_REQUIRED_KEYWORD_PARAMETER_NODE: { @@ -1188,6 +1213,7 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_SYMBOL_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_string(parser, &((pm_symbol_node_t *)node)->unescaped, buffer); break; } @@ -1217,13 +1243,13 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_UNTIL_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_node(parser, (pm_node_t *)((pm_until_node_t *)node)->predicate, buffer); if (((pm_until_node_t *)node)->statements == NULL) { pm_buffer_append_byte(buffer, 0); } else { pm_serialize_node(parser, (pm_node_t *)((pm_until_node_t *)node)->statements, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_WHEN_NODE: { @@ -1240,16 +1266,17 @@ pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { break; } case PM_WHILE_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_node(parser, (pm_node_t *)((pm_while_node_t *)node)->predicate, buffer); if (((pm_while_node_t *)node)->statements == NULL) { pm_buffer_append_byte(buffer, 0); } else { pm_serialize_node(parser, (pm_node_t *)((pm_while_node_t *)node)->statements, buffer); } - pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); break; } case PM_X_STRING_NODE: { + pm_buffer_append_varuint(buffer, (uint32_t)(node->flags & ~PM_NODE_FLAG_COMMON_MASK)); pm_serialize_string(parser, &((pm_x_string_node_t *)node)->unescaped, buffer); break; } @@ -1270,8 +1297,7 @@ pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *bu pm_buffer_append_byte(buffer, (uint8_t) comment->type); // serialize location - pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(comment->start - parser->start)); - pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(comment->end - comment->start)); + pm_serialize_location(parser, &comment->location, buffer); } /** @@ -1326,8 +1352,7 @@ pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buf pm_buffer_append_string(buffer, diagnostic->message, message_length); // serialize location - pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(diagnostic->start - parser->start)); - pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(diagnostic->end - diagnostic->start)); + pm_serialize_location(parser, &diagnostic->location, buffer); } static void @@ -1344,19 +1369,19 @@ pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t * * Serialize the name of the encoding to the buffer. */ void -pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer) { +pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer) { size_t encoding_length = strlen(encoding->name); pm_buffer_append_varuint(buffer, pm_sizet_to_u32(encoding_length)); pm_buffer_append_string(buffer, encoding->name, encoding_length); } -#line 218 "serialize.c.erb" +#line 216 "serialize.c.erb" /** * Serialize the encoding, metadata, nodes, and constant pool. */ void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) { - pm_serialize_encoding(&parser->encoding, buffer); + pm_serialize_encoding(parser->encoding, buffer); pm_buffer_append_varsint(buffer, parser->start_line); pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer); pm_serialize_data_loc(parser, buffer); @@ -1452,7 +1477,7 @@ pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const // Append 0 to mark end of tokens. pm_buffer_append_byte(buffer, 0); - pm_serialize_encoding(&parser.encoding, buffer); + pm_serialize_encoding(parser.encoding, buffer); pm_buffer_append_varsint(buffer, parser.start_line); pm_serialize_comment_list(&parser, &parser.comment_list, buffer); pm_serialize_magic_comment_list(&parser, &parser.magic_comment_list, buffer); diff --git a/src/main/c/yarp/src/util/pm_strpbrk.c b/src/main/c/yarp/src/util/pm_strpbrk.c index ce1f36910b02..115eba1fd2c4 100644 --- a/src/main/c/yarp/src/util/pm_strpbrk.c +++ b/src/main/c/yarp/src/util/pm_strpbrk.c @@ -4,7 +4,7 @@ * This is the slow path that does care about the encoding. */ static inline const uint8_t * -pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum) { +pm_strpbrk_multi_byte(const pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum) { size_t index = 0; while (index < maximum) { @@ -12,7 +12,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t return source + index; } - size_t width = parser->encoding.char_width(source + index, (ptrdiff_t) (maximum - index)); + size_t width = parser->encoding->char_width(source + index, (ptrdiff_t) (maximum - index)); if (width == 0) { return NULL; } @@ -61,10 +61,10 @@ pm_strpbrk_single_byte(const uint8_t *source, const uint8_t *charset, size_t max * need to take a slower path and iterate one multi-byte character at a time. */ const uint8_t * -pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length) { +pm_strpbrk(const pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length) { if (length <= 0) { return NULL; - } else if (parser->encoding_changed && parser->encoding.multibyte) { + } else if (parser->encoding_changed && parser->encoding->multibyte) { return pm_strpbrk_multi_byte(parser, source, charset, (size_t) length); } else { return pm_strpbrk_single_byte(source, charset, (size_t) length); diff --git a/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java b/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java index aa351f8194ad..94416a481498 100644 --- a/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java +++ b/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java @@ -19,6 +19,7 @@ import java.util.TreeSet; import java.util.regex.Matcher; +import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.profiles.Profile; import com.oracle.truffle.api.source.SourceSection; import org.graalvm.collections.Pair; @@ -28,8 +29,10 @@ import org.truffleruby.language.RubyRootNode; import org.truffleruby.language.control.BreakID; import org.truffleruby.language.control.ReturnID; +import org.truffleruby.language.locals.ReadDeclarationVariableNode; import org.truffleruby.language.locals.ReadFrameSlotNode; import org.truffleruby.language.locals.ReadLocalVariableNode; +import org.truffleruby.language.locals.WriteDeclarationVariableNode; import org.truffleruby.language.locals.WriteFrameSlotNode; import org.truffleruby.language.locals.WriteLocalVariableNode; import org.truffleruby.language.methods.CachedLazyCallTargetSupplier; @@ -39,6 +42,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.nodes.RootNode; +import org.truffleruby.parser.BlockDescriptorInfo; public abstract class TruffleASTPrinter { @@ -153,27 +157,49 @@ private static List> getNodeAttributes(Node node) { // map frame slots to local variable names private static Map getNodeAttributeAnnotations(Node node) { final int frameSlot; + final int frameDepth; // ignore WriteDeclarationVariableNode and ReadDeclarationVariableNode // because they access local variable declared in an outer scope, and // it cannot be accessed using the parents chain if (node instanceof WriteLocalVariableNode writeLocalVariableNodeNode) { frameSlot = writeLocalVariableNodeNode.getFrameSlot(); + frameDepth = 0; } else if (node instanceof WriteFrameSlotNode writeFrameSlotNode) { frameSlot = writeFrameSlotNode.getFrameSlot(); + frameDepth = 0; // actually we don't know the depth, but usually it's 0 + } else if (node instanceof WriteDeclarationVariableNode writeDeclarationVariableNode) { + frameSlot = writeDeclarationVariableNode.getFrameSlot(); + frameDepth = writeDeclarationVariableNode.getFrameDepth(); } else if (node instanceof ReadLocalVariableNode readLocalVariableNode) { frameSlot = readLocalVariableNode.getFrameSlot(); + frameDepth = 0; } else if (node instanceof ReadFrameSlotNode readFrameSlotNode) { frameSlot = readFrameSlotNode.getFrameSlot(); + frameDepth = 0; // actually we don't know the depth, but usually it's 0 + } else if (node instanceof ReadDeclarationVariableNode readDeclarationVariableNode) { + frameSlot = readDeclarationVariableNode.getFrameSlot(); + frameDepth = readDeclarationVariableNode.getFrameDepth(); } else { return Collections.emptyMap(); } - final var rootNode = node.getRootNode(); - final var frameDescriptor = rootNode.getFrameDescriptor(); - final String variableName = frameDescriptor.getSlotName(frameSlot).toString(); + FrameDescriptor declarationFrameDescriptor; + RootNode rootNode = node.getRootNode(); + FrameDescriptor frameDescriptor = rootNode.getFrameDescriptor(); + + if (frameDepth > 0) { + // local variable might be declared in some outer scope + declarationFrameDescriptor = BlockDescriptorInfo.getDeclarationFrameDescriptor(frameDescriptor, frameDepth); + } else { + declarationFrameDescriptor = frameDescriptor; + } + + Object slotName = declarationFrameDescriptor.getSlotName(frameSlot); + assert slotName != null; // all the mentioned above classes use the same field name - "frameSlot", so just hardcode it + final String variableName = slotName.toString(); return Collections.singletonMap("frameSlot", variableName); } diff --git a/src/main/java/org/truffleruby/language/locals/WriteDeclarationVariableNode.java b/src/main/java/org/truffleruby/language/locals/WriteDeclarationVariableNode.java index dd7111327303..cfdbe3806487 100644 --- a/src/main/java/org/truffleruby/language/locals/WriteDeclarationVariableNode.java +++ b/src/main/java/org/truffleruby/language/locals/WriteDeclarationVariableNode.java @@ -29,6 +29,10 @@ public WriteDeclarationVariableNode(int frameSlot, int frameDepth, RubyNode valu this.frameDepth = frameDepth; } + public int getFrameDepth() { + return frameDepth; + } + @Override public Object execute(VirtualFrame frame) { final Object value = valueNode.execute(frame); diff --git a/src/main/java/org/truffleruby/parser/BodyTranslator.java b/src/main/java/org/truffleruby/parser/BodyTranslator.java index e5a1e5351e51..55085a745c17 100644 --- a/src/main/java/org/truffleruby/parser/BodyTranslator.java +++ b/src/main/java/org/truffleruby/parser/BodyTranslator.java @@ -1547,8 +1547,6 @@ public RubyNode visitForNode(ForParseNode node) { * Here, JRuby calls the object being iterated over the 'iter'. */ final String temp = environment.allocateLocalTemp("for"); - environment.declareVar(temp); - final ParseNode receiver = node.getIterNode(); /* The x in for x in ... is like the nodes in multiple assignment - it has a dummy RHS which we need to replace @@ -1822,7 +1820,7 @@ private RubyNode translateBlockLikeNode(IterParseNode node, boolean isStabbyLamb final ArgsParseNode argsNode = node.getArgsNode(); // Unset this flag for any blocks within the `for` statement's body - final boolean hasOwnScope = isStabbyLambda || !translatingForStatement; + final boolean hasOwnScope = !translatingForStatement; final boolean isProc = !isStabbyLambda; @@ -2890,9 +2888,9 @@ private RubyNode translateWhileNode(WhileParseNode node, boolean conditionInvers @Override public RubyNode visitXStrNode(XStrParseNode node) { - final ParseNode argsNode = buildArrayNode( - node.getPosition(), - new StrParseNode(node.getPosition(), node.getValue(), node.encoding)); + final var stringNode = new StrParseNode(node.getPosition(), node.getValue(), node.encoding); + stringNode.setFrozen(true); // it's always frozen + final ParseNode argsNode = buildArrayNode(node.getPosition(), stringNode); final ParseNode callNode = new FCallParseNode(node.getPosition(), "`", argsNode, null); final RubyNode ret = callNode.accept(this); return addNewlineIfNeeded(node, ret); diff --git a/src/main/java/org/truffleruby/parser/YARPLoadArgumentsTranslator.java b/src/main/java/org/truffleruby/parser/YARPLoadArgumentsTranslator.java index a5d7dead4fa6..d7c9d1f969ff 100644 --- a/src/main/java/org/truffleruby/parser/YARPLoadArgumentsTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPLoadArgumentsTranslator.java @@ -262,7 +262,6 @@ public RubyNode visitImplicitRestNode(Nodes.ImplicitRestNode node) { throw CompilerDirectives.shouldNotReachHere("handled in #translateWithParameters"); } - @Override public RubyNode visitKeywordRestParameterNode(Nodes.KeywordRestParameterNode node) { final RubyNode readNode = new ReadKeywordRestArgumentNode(language, arity); diff --git a/src/main/java/org/truffleruby/parser/YARPMultiTargetNodeTranslator.java b/src/main/java/org/truffleruby/parser/YARPMultiTargetNodeTranslator.java index f6afcf6c1a02..2086e7cb8747 100644 --- a/src/main/java/org/truffleruby/parser/YARPMultiTargetNodeTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPMultiTargetNodeTranslator.java @@ -89,8 +89,8 @@ public AssignableNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode } @Override - public AssignableNode visitCallNode(Nodes.CallNode node) { - final RubyNode rubyNode = yarpTranslator.translateCallTargetNode(node); + public AssignableNode visitCallTargetNode(Nodes.CallTargetNode node) { + final RubyNode rubyNode = node.accept(yarpTranslator); return ((AssignableNode) rubyNode).toAssignableNode(); } @@ -112,6 +112,12 @@ public AssignableNode visitGlobalVariableTargetNode(Nodes.GlobalVariableTargetNo return ((AssignableNode) rubyNode).toAssignableNode(); } + @Override + public AssignableNode visitIndexTargetNode(Nodes.IndexTargetNode node) { + final RubyNode rubyNode = node.accept(yarpTranslator); + return ((AssignableNode) rubyNode).toAssignableNode(); + } + @Override public AssignableNode visitInstanceVariableTargetNode(Nodes.InstanceVariableTargetNode node) { final RubyNode rubyNode = node.accept(yarpTranslator); @@ -142,6 +148,7 @@ public AssignableNode visitSplatNode(Nodes.SplatNode node) { } @Override + // RequiredParameterNode is handled during destructuring method/proc arguments public AssignableNode visitRequiredParameterNode(Nodes.RequiredParameterNode node) { // TODO: this could be done more directly but the logic of visitLocalVariableWriteNode() needs to be simpler first // NOTE: depth is not supposed to be used anyway so pass 0 value. diff --git a/src/main/java/org/truffleruby/parser/YARPMultiWriteNodeTranslator.java b/src/main/java/org/truffleruby/parser/YARPMultiWriteNodeTranslator.java index 9ab5d51f6f57..5c74a310c5f1 100644 --- a/src/main/java/org/truffleruby/parser/YARPMultiWriteNodeTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPMultiWriteNodeTranslator.java @@ -9,6 +9,7 @@ */ package org.truffleruby.parser; +import com.oracle.truffle.api.CompilerDirectives; import org.prism.AbstractNodeVisitor; import org.prism.Nodes; import org.truffleruby.RubyLanguage; @@ -50,7 +51,13 @@ public RubyNode translate() { final AssignableNode restNode; if (node.rest != null) { - restNode = node.rest.accept(this); + if (node.rest instanceof Nodes.ImplicitRestNode) { + // a, = [] + // do nothing + restNode = null; + } else { + restNode = node.rest.accept(this); + } } else { restNode = null; } @@ -76,8 +83,8 @@ public AssignableNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode } @Override - public AssignableNode visitCallNode(Nodes.CallNode node) { - final RubyNode rubyNode = yarpTranslator.translateCallTargetNode(node); + public AssignableNode visitCallTargetNode(Nodes.CallTargetNode node) { + final RubyNode rubyNode = node.accept(yarpTranslator); return ((AssignableNode) rubyNode).toAssignableNode(); } @@ -99,6 +106,17 @@ public AssignableNode visitGlobalVariableTargetNode(Nodes.GlobalVariableTargetNo return ((AssignableNode) rubyNode).toAssignableNode(); } + @Override + public AssignableNode visitImplicitRestNode(Nodes.ImplicitRestNode node) { + throw CompilerDirectives.shouldNotReachHere("handled in #translate"); + } + + @Override + public AssignableNode visitIndexTargetNode(Nodes.IndexTargetNode node) { + final RubyNode rubyNode = node.accept(yarpTranslator); + return ((AssignableNode) rubyNode).toAssignableNode(); + } + @Override public AssignableNode visitInstanceVariableTargetNode(Nodes.InstanceVariableTargetNode node) { final RubyNode rubyNode = node.accept(yarpTranslator); diff --git a/src/main/java/org/truffleruby/parser/YARPTranslator.java b/src/main/java/org/truffleruby/parser/YARPTranslator.java index bb9cc6ba2a1f..5b795bb4d53e 100644 --- a/src/main/java/org/truffleruby/parser/YARPTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPTranslator.java @@ -215,6 +215,9 @@ public class YARPTranslator extends AbstractNodeVisitor { "_9" }; + // all the encountered BEGIN {} blocks + private final ArrayList beginBlocks = new ArrayList<>(); + public YARPTranslator( RubyLanguage language, TranslatorEnvironment environment, @@ -469,7 +472,9 @@ private RubyNode visitBlockNode(Nodes.BlockNode node, String literalBlockPassedT private RubyNode translateBlockAndLambda(Nodes.Node node, Nodes.Node parametersNode, Nodes.Node body, String[] locals, String literalBlockPassedToMethod) { final boolean isStabbyLambda = node instanceof Nodes.LambdaNode; - final boolean hasOwnScope = true; + + // Unset this flag for a `for`-loop's block + final boolean hasOwnScope = !translatingForStatement; TranslatorEnvironment methodParent = environment.getSurroundingMethodEnvironment(); final String methodName = methodParent.getMethodName(); @@ -594,10 +599,16 @@ public RubyNode visitCallAndWriteNode(Nodes.CallAndWriteNode node) { final var writeReceiverNode = receiverExpression.getWriteNode(); final var readReceiver = receiverExpression.getReadYARPNode(); - // Use Prism nodes and rely on CallNode translation to automatically set - // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`) - final RubyNode readNode = callNode(node, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY).accept(this); - final RubyNode writeNode = callNode(node, readReceiver, node.write_name, node.value).accept(this); + // Use Prism nodes and rely on CallNode translation to automatically set RubyCallNode attributes. + // Prism doesn't set ATTRIBUTE_WRITE flag, so we should add it manually + // safe navigation flag is handled separately, so as optimisation remove it from the flags + short writeFlags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + writeFlags = (short) (writeFlags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + short readFlags = (short) (node.flags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + final RubyNode readNode = callNode(node, readFlags, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY) + .accept(this); + final RubyNode writeNode = callNode(node, writeFlags, readReceiver, node.write_name, + node.value).accept(this); final RubyNode andNode = AndNodeGen.create(readNode, writeNode); final RubyNode sequence; @@ -622,15 +633,7 @@ public RubyNode visitCallNode(Nodes.CallNode node) { var argumentsAndBlock = translateArgumentsAndBlock(node.arguments, node.block, methodName); var translatedArguments = argumentsAndBlock.arguments(); - // If the receiver is explicit or implicit 'self' then we can call private methods - final boolean ignoreVisibility = node.receiver == null || node.receiver instanceof Nodes.SelfNode; - final boolean isVariableCall = node.isVariableCall(); - // This isn't fully accurate and doesn't handle cases like #===, #!=, a.foo=(42) - // the issue is tracked in https://github.com/ruby/prism/issues/1715 - final boolean isAttrAssign = isAttrAssign(node.name); - final boolean isSafeNavigation = node.isSafeNavigation(); - - if (environment.getParseEnvironment().inCore() && isVariableCall && methodName.equals("undefined")) { + if (environment.getParseEnvironment().inCore() && node.isVariableCall() && methodName.equals("undefined")) { // translate undefined final RubyNode rubyNode = new ObjectLiteralNode(NotProvided.INSTANCE); return assignPositionAndFlags(node, rubyNode); @@ -666,10 +669,10 @@ public RubyNode visitCallNode(Nodes.CallNode node) { argumentsAndBlock.argumentsDescriptor(), translatedArguments, argumentsAndBlock.isSplatted(), - ignoreVisibility, - isVariableCall, - isSafeNavigation, - isAttrAssign); + node.isIgnoreVisibility(), + node.isVariableCall(), + node.isSafeNavigation(), + node.isAttributeWrite()); final RubyNode callNode = language.coreMethodAssumptions.createCallNode(callNodeParameters); final var rubyNode = wrapCallWithLiteralBlock(argumentsAndBlock, callNode); @@ -776,14 +779,6 @@ private ArgumentsDescriptor getKeywordArgumentsDescriptor(Nodes.Node[] arguments } } - private boolean isAttrAssign(String methodName) { - if (!methodName.endsWith("=") || methodName.length() < 2) { - return false; - } - char before = methodName.charAt(methodName.length() - 2); - return before != '=' && before != '!' && before != '<' && before != '>'; - } - @Override public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) { // e.g. `a.b += value` is translated into `a.b = a.b + value`, @@ -795,11 +790,15 @@ public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) { final var writeReceiverNode = receiverExpression.getWriteNode(); final var readReceiver = receiverExpression.getReadYARPNode(); - // Use Prism nodes and rely on CallNode translation to automatically set - // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`) - final Nodes.Node read = callNode(node, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY); + // Use Prism nodes and rely on CallNode translation to automatically set CallNode flags + // safe navigation flag is handled separately, so as optimisation remove it from the flags + short writeFlags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + writeFlags = (short) (writeFlags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + short readFlags = (short) (node.flags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + final Nodes.Node read = callNode(node, readFlags, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY); final Nodes.Node executeOperator = callNode(node, read, node.operator, node.value); - final Nodes.Node write = callNode(node, readReceiver, node.write_name, executeOperator); + final Nodes.Node write = callNode(node, writeFlags, readReceiver, node.write_name, + executeOperator); final RubyNode writeNode = write.accept(this); final RubyNode rubyNode; @@ -828,10 +827,16 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) { final var writeReceiverNode = receiverExpression.getWriteNode(); final var readReceiver = receiverExpression.getReadYARPNode(); - // Use Prism nodes and rely on CallNode translation to automatically set - // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`) - final RubyNode readNode = callNode(node, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY).accept(this); - final RubyNode writeNode = callNode(node, readReceiver, node.write_name, node.value).accept(this); + // Use Prism nodes and rely on CallNode translation to automatically set CallNode flags + // Prism doesn't set ATTRIBUTE_WRITE flag, so we should add it manually + // safe navigation flag is handled separately, so as optimisation remove it from the flags + short writeFlags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + writeFlags = (short) (writeFlags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + short readFlags = (short) (node.flags & ~Nodes.CallNodeFlags.SAFE_NAVIGATION); + final RubyNode readNode = callNode(node, readFlags, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY) + .accept(this); + final RubyNode writeNode = callNode(node, writeFlags, readReceiver, node.write_name, + node.value).accept(this); final RubyNode orNode = OrNodeGen.create(readNode, writeNode); final RubyNode sequence; @@ -848,6 +853,23 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) { return assignPositionAndFlags(node, rubyNode); } + public RubyNode visitCallTargetNode(Nodes.CallTargetNode node) { + // extra argument should be added before node translation + // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen) + // that relies on arguments count + assert node.name.endsWith("="); + + final Nodes.Node[] arguments = { new Nodes.NilNode(0, 0) }; + final var argumentsNode = new Nodes.ArgumentsNode(NO_FLAGS, arguments, 0, 0); + + // Prism may set SAFE_NAVIGATION flag + short flags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + + final var callNode = new Nodes.CallNode(flags, node.receiver, node.name, argumentsNode, null, + node.startOffset, node.length); + return callNode.accept(this); + } + @Override public RubyNode visitCapturePatternNode(Nodes.CapturePatternNode node) { return defaultVisit(node); @@ -1517,9 +1539,134 @@ public RubyNode visitFloatNode(Nodes.FloatNode node) { return assignPositionAndFlags(node, rubyNode); } + /** A Ruby for-loop, such as: + * + *
+     * for x in y
+     *     z = 0
+     *     puts x
+     * end
+     * 
+ * + * naively desugars to: + * + *
+     * y.each do |x|
+     *     z = 0
+     *     puts x
+     * end
+     * 
+ * + * The main difference is that z and x are always going to be local to the scope outside the block, so it's a bit + * more like: + * + *
+     * z = nil  #  unless z is already defined
+     * x = nil  #  unless x is already defined
+     *
+     * y.each do |temp|
+     *    x = temp
+     *    z = 0
+     *    puts x
+     * end
+     * 
+ * + * Assigning x the temporary variable instead of defining x as a block parameter forces x to be defined in a proper + * scope. + * + * It also handles cases when the expression assigned in the for could is index assignment (a[b] in []), attribute + * assignment (a.b in []), multiple assignment (a, b, c in []), or whatever: + * + *
+     * for x[0] in y
+     *     puts x[0]
+     * end
+     * 
+ * + * http://blog.grayproductions.net/articles/the_evils_of_the_for_loop + * http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby + * + * The other complication is that normal locals should be defined in the enclosing scope, unlike a normal block. We + * do that by setting a flag on this translator object when we visit the new iter, translatingForStatement, which we + * recognise when visiting a block node. */ @Override public RubyNode visitForNode(Nodes.ForNode node) { - return defaultVisit(node); + final String parameterName = environment.allocateLocalTemp("for"); + + final var requireds = new Nodes.Node[]{ new Nodes.RequiredParameterNode(parameterName, 0, 0) }; + final var parameters = new Nodes.ParametersNode(requireds, Nodes.Node.EMPTY_ARRAY, null, Nodes.Node.EMPTY_ARRAY, + Nodes.Node.EMPTY_ARRAY, null, null, 0, 0); + final var blockParameters = new Nodes.BlockParametersNode(parameters, Nodes.Node.EMPTY_ARRAY, 0, 0); + + final var readParameter = new Nodes.LocalVariableReadNode(parameterName, 0, 0, 0); + final Nodes.Node writeIndex; + + // replace -Target node with a -Write one + if (node.index instanceof Nodes.LocalVariableTargetNode target) { + writeIndex = new Nodes.LocalVariableWriteNode(target.name, target.depth, readParameter, 0, 0); + } else if (node.index instanceof Nodes.InstanceVariableTargetNode target) { + writeIndex = new Nodes.InstanceVariableWriteNode(target.name, readParameter, 0, 0); + } else if (node.index instanceof Nodes.ClassVariableTargetNode target) { + writeIndex = new Nodes.ClassVariableWriteNode(target.name, readParameter, 0, 0); + } else if (node.index instanceof Nodes.GlobalVariableTargetNode target) { + writeIndex = new Nodes.GlobalVariableWriteNode(target.name, readParameter, 0, 0); + } else if (node.index instanceof Nodes.ConstantTargetNode target) { + writeIndex = new Nodes.ConstantWriteNode(target.name, readParameter, 0, 0); + } else if (node.index instanceof Nodes.ConstantPathTargetNode target) { + final var constantPath = new Nodes.ConstantPathNode(target.parent, target.child, 0, 0); + writeIndex = new Nodes.ConstantPathWriteNode(constantPath, readParameter, 0, 0); + } else if (node.index instanceof Nodes.CallTargetNode target) { + final var arguments = new Nodes.ArgumentsNode(NO_FLAGS, new Nodes.Node[]{ readParameter }, 0, 0); + + // preserve target flags because they can contain SAFE_NAVIGATION flag + short flags = (short) (target.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + + writeIndex = new Nodes.CallNode(flags, target.receiver, target.name, arguments, null, 0, 0); + } else if (node.index instanceof Nodes.IndexTargetNode target) { + final Nodes.ArgumentsNode arguments; + final Nodes.Node[] statements; + + if (target.arguments != null) { + statements = new Nodes.Node[target.arguments.arguments.length + 1]; + System.arraycopy(target.arguments.arguments, 0, statements, 0, target.arguments.arguments.length); + } else { + statements = new Nodes.Node[1]; + } + + statements[statements.length - 1] = readParameter; + arguments = new Nodes.ArgumentsNode(NO_FLAGS, statements, 0, 0); + + writeIndex = new Nodes.CallNode(target.flags, target.receiver, "[]=", arguments, target.block, 0, 0); + } else if (node.index instanceof Nodes.MultiTargetNode target) { + writeIndex = new Nodes.MultiWriteNode(target.lefts, target.rest, target.rights, readParameter, 0, 0); + } else { + throw CompilerDirectives.shouldNotReachHere("Unexpected node class for for-loop index"); + } + + Nodes.Node[] statements = new Nodes.Node[node.statements.body.length + 1]; + System.arraycopy(node.statements.body, 0, statements, 1, node.statements.body.length); + statements[0] = writeIndex; + + final Nodes.Node body = new Nodes.StatementsNode(statements, node.statements.startOffset, + node.statements.length); + // in the block environment declare local variable only for parameter + // and skip declaration all the local variables defined in the block + String[] locals = new String[]{ parameterName }; + final var block = new Nodes.BlockNode(locals, 0, blockParameters, body, 0, 0); + final var eachCall = new Nodes.CallNode(NO_FLAGS, node.collection, "each", null, block, node.startOffset, + node.length); + + final RubyNode rubyNode; + final boolean translatingForStatement = this.translatingForStatement; + this.translatingForStatement = true; + + try { + rubyNode = eachCall.accept(this); + } finally { + this.translatingForStatement = translatingForStatement; + } + + return rubyNode; } @Override @@ -1753,7 +1900,7 @@ public RubyNode visitIndexAndWriteNode(Nodes.IndexAndWriteNode node) { } final RubyNode rubyNode = translateIndexOrAndIndexAndWriteNodes(true, node.receiver, arguments, node.block, - node.value); + node.value, node.flags); return assignPositionAndFlags(node, rubyNode); } @@ -1803,16 +1950,17 @@ public RubyNode visitIndexOperatorWriteNode(Nodes.IndexOperatorWriteNode node) { readArguments[i] = expression.getReadYARPNode(); } - final Nodes.Node read = new Nodes.CallNode(readReceiver, "[]", - new Nodes.ArgumentsNode(readArguments, (short) 0, 0, 0), blockArgument, (short) 0, 0, 0); + final Nodes.Node read = new Nodes.CallNode(node.flags, readReceiver, "[]", + new Nodes.ArgumentsNode(NO_FLAGS, readArguments, 0, 0), blockArgument, 0, 0); final Nodes.Node executeOperator = callNode(node, read, node.operator, node.value); final Nodes.Node[] readArgumentsAndResult = new Nodes.Node[argumentsCount + 1]; System.arraycopy(readArguments, 0, readArgumentsAndResult, 0, argumentsCount); readArgumentsAndResult[argumentsCount] = executeOperator; - final Nodes.Node write = new Nodes.CallNode(readReceiver, "[]=", - new Nodes.ArgumentsNode(readArgumentsAndResult, (short) 0, 0, 0), blockArgument, (short) 0, 0, 0); + short writeFlags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + final Nodes.Node write = new Nodes.CallNode(writeFlags, readReceiver, "[]=", + new Nodes.ArgumentsNode(NO_FLAGS, readArgumentsAndResult, 0, 0), blockArgument, 0, 0); final RubyNode writeNode = write.accept(this); final RubyNode writeArgumentsNode = sequence(Arrays.asList(writeArgumentsNodes)); final RubyNode rubyNode; @@ -1838,12 +1986,46 @@ public RubyNode visitIndexOrWriteNode(Nodes.IndexOrWriteNode node) { } final RubyNode rubyNode = translateIndexOrAndIndexAndWriteNodes(false, node.receiver, arguments, node.block, - node.value); + node.value, node.flags); return assignPositionAndFlags(node, rubyNode); } + public RubyNode visitIndexTargetNode(Nodes.IndexTargetNode node) { + // extra argument should be added before node translation + // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen) + // that relies on arguments count + + final Nodes.Node[] arguments; + final Nodes.ArgumentsNode argumentsNode; + + if (node.arguments == null) { + arguments = new Nodes.Node[1]; + } else { + arguments = new Nodes.Node[node.arguments.arguments.length + 1]; + for (int i = 0; i < node.arguments.arguments.length; i++) { + arguments[i] = node.arguments.arguments[i]; + } + } + + arguments[arguments.length - 1] = new Nodes.NilNode(0, 0); + + if (node.arguments == null) { + argumentsNode = new Nodes.ArgumentsNode(NO_FLAGS, arguments, 0, 0); + } else { + argumentsNode = new Nodes.ArgumentsNode(node.arguments.flags, arguments, node.arguments.startOffset, + node.arguments.length); + } + + short writeFlags = (short) (node.flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + final var callNode = new Nodes.CallNode(writeFlags, node.receiver, "[]=", argumentsNode, node.block, + node.startOffset, + node.length); + return callNode.accept(this); + } + + private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, Nodes.Node receiver, - Nodes.Node[] arguments, Nodes.Node block, Nodes.Node value) { + Nodes.Node[] arguments, Nodes.Node block, Nodes.Node value, short flags) { // Handle both &&= and ||= operators: // `a[b] ||= c` is translated into `a[b] || a[b] = c` // `a[b] &&= c` is translated into `a[b] && a[b] = c` @@ -1881,16 +2063,17 @@ private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, No blockArgument = null; } - final Nodes.Node read = new Nodes.CallNode(readReceiver, "[]", - new Nodes.ArgumentsNode(readArguments, (short) 0, 0, 0), blockArgument, (short) 0, 0, 0); + final Nodes.Node read = new Nodes.CallNode(flags, readReceiver, "[]", + new Nodes.ArgumentsNode(NO_FLAGS, readArguments, 0, 0), blockArgument, 0, 0); final RubyNode readNode = read.accept(this); final Nodes.Node[] readArgumentsAndValue = new Nodes.Node[arguments.length + 1]; System.arraycopy(readArguments, 0, readArgumentsAndValue, 0, arguments.length); readArgumentsAndValue[arguments.length] = value; - final Nodes.Node write = new Nodes.CallNode(readReceiver, "[]=", - new Nodes.ArgumentsNode(readArgumentsAndValue, (short) 0, 0, 0), blockArgument, (short) 0, 0, 0); + short writeFlags = (short) (flags | Nodes.CallNodeFlags.ATTRIBUTE_WRITE); + final Nodes.Node write = new Nodes.CallNode(writeFlags, readReceiver, "[]=", + new Nodes.ArgumentsNode(NO_FLAGS, readArgumentsAndValue, 0, 0), blockArgument, 0, 0); final RubyNode writeNode = write.accept(this); final RubyNode operatorNode; @@ -1991,7 +2174,7 @@ public RubyNode visitIntegerNode(Nodes.IntegerNode node) { public RubyNode visitInterpolatedMatchLastLineNode(Nodes.InterpolatedMatchLastLineNode node) { // replace regexp with /.../ =~ $_ - final var regexp = new Nodes.InterpolatedRegularExpressionNode(node.parts, node.flags, node.startOffset, + final var regexp = new Nodes.InterpolatedRegularExpressionNode(node.flags, node.parts, node.startOffset, node.length); final var regexpNode = regexp.accept(this); final var lastLineNode = ReadGlobalVariableNodeGen.create("$_"); @@ -2200,7 +2383,7 @@ public RubyNode visitLocalVariableTargetNode(Nodes.LocalVariableTargetNode node) public RubyNode visitMatchLastLineNode(Nodes.MatchLastLineNode node) { // replace regexp with /.../ =~ $_ - final var regexp = new Nodes.RegularExpressionNode(node.unescaped, node.flags, node.startOffset, node.length); + final var regexp = new Nodes.RegularExpressionNode(node.flags, node.unescaped, node.startOffset, node.length); final var regexpNode = regexp.accept(this); final var lastLineNode = ReadGlobalVariableNodeGen.create("$_"); @@ -2382,17 +2565,37 @@ public RubyNode visitPinnedVariableNode(Nodes.PinnedVariableNode node) { @Override public RubyNode visitPostExecutionNode(Nodes.PostExecutionNode node) { - return defaultVisit(node); + // END blocks run after any other code - not just code in the same file + // Turn into a call to Truffle::KernelOperations.at_exit + + // Create Prism CallNode to avoid duplication block literal related logic + final var receiver = new Nodes.ConstantReadNode("KernelOperations", 0, 0); + final var arguments = new Nodes.ArgumentsNode(NO_FLAGS, new Nodes.Node[]{ new Nodes.FalseNode(0, 0) }, 0, 0); + final var block = new Nodes.BlockNode(StringUtils.EMPTY_STRING_ARRAY, 0, null, node.statements, 0, 0); + + final var callNode = new Nodes.CallNode(NO_FLAGS, receiver, "at_exit", arguments, block, 0, 0).accept(this); + final RubyNode rubyNode = new OnceNode(callNode); + return assignPositionAndFlags(node, rubyNode); } @Override public RubyNode visitPreExecutionNode(Nodes.PreExecutionNode node) { - return defaultVisit(node); + beginBlocks.add(node); + return null; } @Override public RubyNode visitProgramNode(Nodes.ProgramNode node) { - return node.statements.accept(this); + final RubyNode sequence = node.statements.accept(this); + + // add BEGIN {} blocks at the very beginning of the program + ArrayList nodes = new ArrayList<>(); + for (var begin : beginBlocks) { + nodes.add(begin.statements.accept(this)); + } + + nodes.add(sequence); + return sequence(node, nodes); } @Override @@ -2477,10 +2680,11 @@ public RubyNode visitRedoNode(Nodes.RedoNode node) { @Override public RubyNode visitRegularExpressionNode(Nodes.RegularExpressionNode node) { - var source = toTString(node.unescaped); var encodingAndOptions = getRegexpEncodingAndOptions(new Nodes.RegularExpressionFlags(node.flags)); + var encoding = encodingAndOptions.encoding; + var source = TruffleString.fromByteArrayUncached(node.unescaped, encoding.tencoding, false); try { - final RubyRegexp regexp = RubyRegexp.create(language, source, encodingAndOptions.encoding, + final RubyRegexp regexp = RubyRegexp.create(language, source, encoding, encodingAndOptions.options, currentNode); final ObjectLiteralNode literalNode = new ObjectLiteralNode(regexp); return assignPositionAndFlags(node, literalNode); @@ -2493,10 +2697,13 @@ private record RegexpEncodingAndOptions(RubyEncoding encoding, RegexpOptions opt } private RegexpEncodingAndOptions getRegexpEncodingAndOptions(Nodes.RegularExpressionFlags flags) { + RubyEncoding regexpEncoding; + + // regexp options final KCode kcode; - final RubyEncoding regexpEncoding; final boolean fixed; boolean explicitEncoding = true; + if (flags.isAscii8bit()) { fixed = false; kcode = KCode.NONE; @@ -2520,6 +2727,16 @@ private RegexpEncodingAndOptions getRegexpEncodingAndOptions(Nodes.RegularExpres explicitEncoding = false; } + if (!explicitEncoding) { + if (flags.isForcedBinaryEncoding()) { + regexpEncoding = Encodings.BINARY; + } else if (flags.isForcedUsAsciiEncoding()) { + regexpEncoding = Encodings.US_ASCII; + } else if (flags.isForcedUtf8Encoding()) { + regexpEncoding = Encodings.UTF_8; + } + } + final RegexpOptions options = new RegexpOptions(kcode, fixed, flags.isOnce(), flags.isExtended(), flags.isMultiLine(), flags.isIgnoreCase(), flags.isAscii8bit(), !explicitEncoding, true); return new RegexpEncodingAndOptions(regexpEncoding, options); @@ -2668,13 +2885,23 @@ public RubyNode visitStatementsNode(Nodes.StatementsNode node) { @Override public RubyNode visitStringNode(Nodes.StringNode node) { final RubyNode rubyNode; - final TruffleString tstring = TStringUtils.fromByteArray(node.unescaped, sourceEncoding); + final RubyEncoding encoding; + + if (node.isForcedUtf8Encoding()) { + encoding = Encodings.UTF_8; + } else if (node.isForcedBinaryEncoding()) { + encoding = Encodings.BINARY; + } else { + encoding = sourceEncoding; + } + + final TruffleString tstring = TStringUtils.fromByteArray(node.unescaped, encoding); if (!node.isFrozen()) { - final TruffleString cachedTString = language.tstringCache.getTString(tstring, sourceEncoding); - rubyNode = new StringLiteralNode(cachedTString, sourceEncoding); + final TruffleString cachedTString = language.tstringCache.getTString(tstring, encoding); + rubyNode = new StringLiteralNode(cachedTString, encoding); } else { - final ImmutableRubyString frozenString = language.getFrozenStringLiteral(tstring, sourceEncoding); + final ImmutableRubyString frozenString = language.getFrozenStringLiteral(tstring, encoding); rubyNode = new FrozenStringLiteralNode(frozenString, FrozenStrings.EXPRESSION); } @@ -2707,8 +2934,21 @@ private RubyNode executeOrInheritBlock(RubyNode blockNode) { @Override public RubyNode visitSymbolNode(Nodes.SymbolNode node) { - var tstring = TStringUtils.fromByteArray(node.unescaped, sourceEncoding); - final RubySymbol symbol = language.getSymbol(tstring, sourceEncoding); + final RubyEncoding encoding; + + if (node.isForcedUtf8Encoding()) { + encoding = Encodings.UTF_8; + } else if (node.isForcedUsAsciiEncoding()) { + encoding = Encodings.US_ASCII; + } else if (node.isForcedBinaryEncoding()) { + encoding = Encodings.BINARY; + } else { + encoding = sourceEncoding; + } + + var tstring = TStringUtils.fromByteArray(node.unescaped, encoding); + final RubySymbol symbol = language.getSymbol(tstring, encoding); + final RubyNode rubyNode = new ObjectLiteralNode(symbol); return assignPositionAndFlags(node, rubyNode); } @@ -2766,8 +3006,18 @@ public RubyNode visitWhileNode(Nodes.WhileNode node) { @Override public RubyNode visitXStringNode(Nodes.XStringNode node) { - // TODO: pass flags, needs https://github.com/ruby/yarp/issues/1567 - var stringNode = new Nodes.StringNode((short) 0, node.unescaped, node.startOffset, node.length); + // convert EncodingFlags to StringFlags + int flags = Nodes.StringFlags.FROZEN; // it's always frozen + + if (node.isForcedBinaryEncoding()) { + flags |= Nodes.StringFlags.FORCED_BINARY_ENCODING; + } + + if (node.isForcedUtf8Encoding()) { + flags |= Nodes.StringFlags.FORCED_UTF8_ENCODING; + } + + var stringNode = new Nodes.StringNode((short) flags, node.unescaped, node.startOffset, node.length); final RubyNode string = stringNode.accept(this); final RubyNode rubyNode = createCallNode(new SelfNode(), "`", string); @@ -3112,51 +3362,12 @@ private RubyNode translateControlFlowArguments(Nodes.ArgumentsNode node) { return assignPositionAndFlags(node, rubyNode); } - private RubyNode translateRescueException(Nodes.Node exception) { - final RubyNode rubyNode; - - if (exception instanceof Nodes.CallNode callNode) { - rubyNode = translateCallTargetNode(callNode); - } else { - rubyNode = exception.accept(this); - } - + private RubyNode translateRescueException(Nodes.Node target) { + final RubyNode rubyNode = target.accept(this); final AssignableNode assignableNode = (AssignableNode) rubyNode; return new AssignRescueVariableNode(assignableNode); } - public RubyNode translateCallTargetNode(Nodes.CallNode node) { - // extra argument should be added before node translation - // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen) - // that relies on arguments count - if (node.name.endsWith("=")) { - final Nodes.Node[] arguments; - final Nodes.ArgumentsNode argumentsNode; - - if (node.arguments == null) { - arguments = new Nodes.Node[1]; - } else { - arguments = new Nodes.Node[node.arguments.arguments.length + 1]; - for (int i = 0; i < node.arguments.arguments.length; i++) { - arguments[i] = node.arguments.arguments[i]; - } - } - - arguments[arguments.length - 1] = new Nodes.NilNode(0, 0); - - if (node.arguments == null) { - argumentsNode = new Nodes.ArgumentsNode(arguments, (short) 0, 0, 0); - } else { - argumentsNode = new Nodes.ArgumentsNode(arguments, node.arguments.flags, node.arguments.startOffset, - node.arguments.length); - } - node = new Nodes.CallNode(node.receiver, node.name, argumentsNode, node.block, node.flags, node.startOffset, - node.length); - } - - return node.accept(this); - } - private RubyNode translateWhileNode(Nodes.Node node, Nodes.Node predicate, Nodes.StatementsNode statements, boolean conditionInversed, boolean evaluateConditionBeforeBody) { RubyNode condition = predicate.accept(this); @@ -3318,8 +3529,13 @@ protected static RubyNode sequence(List sequence) { protected static Nodes.CallNode callNode(Nodes.Node location, Nodes.Node receiver, String methodName, Nodes.Node... arguments) { - return new Nodes.CallNode(receiver, methodName, - new Nodes.ArgumentsNode(arguments, NO_FLAGS, location.startOffset, location.length), null, NO_FLAGS, + return callNode(location, NO_FLAGS, receiver, methodName, arguments); + } + + protected static Nodes.CallNode callNode(Nodes.Node location, short flags, Nodes.Node receiver, String methodName, + Nodes.Node... arguments) { + return new Nodes.CallNode(flags, receiver, methodName, + new Nodes.ArgumentsNode(NO_FLAGS, arguments, location.startOffset, location.length), null, location.startOffset, location.length); } diff --git a/src/yarp/java/org/prism/AbstractNodeVisitor.java b/src/yarp/java/org/prism/AbstractNodeVisitor.java index 4de522bb1f65..fb34d20f83bd 100644 --- a/src/yarp/java/org/prism/AbstractNodeVisitor.java +++ b/src/yarp/java/org/prism/AbstractNodeVisitor.java @@ -96,6 +96,10 @@ public T visitCallOrWriteNode(Nodes.CallOrWriteNode node) { return defaultVisit(node); } + public T visitCallTargetNode(Nodes.CallTargetNode node) { + return defaultVisit(node); + } + public T visitCapturePatternNode(Nodes.CapturePatternNode node) { return defaultVisit(node); } @@ -304,6 +308,10 @@ public T visitIndexOrWriteNode(Nodes.IndexOrWriteNode node) { return defaultVisit(node); } + public T visitIndexTargetNode(Nodes.IndexTargetNode node) { + return defaultVisit(node); + } + public T visitInstanceVariableAndWriteNode(Nodes.InstanceVariableAndWriteNode node) { return defaultVisit(node); } diff --git a/src/yarp/java/org/prism/Loader.java b/src/yarp/java/org/prism/Loader.java index 60421d582227..f79f180e4369 100644 --- a/src/yarp/java/org/prism/Loader.java +++ b/src/yarp/java/org/prism/Loader.java @@ -98,7 +98,7 @@ protected ParseResult load() { expect((byte) 'M', "incorrect prism header"); expect((byte) 0, "prism version does not match"); - expect((byte) 18, "prism version does not match"); + expect((byte) 19, "prism version does not match"); expect((byte) 0, "prism version does not match"); expect((byte) 1, "Loader.java requires no location fields in the serialized output"); @@ -309,9 +309,9 @@ private Nodes.Node loadNode() { case 4: return new Nodes.AndNode(loadNode(), loadNode(), startOffset, length); case 5: - return new Nodes.ArgumentsNode(loadNodes(), loadFlags(), startOffset, length); + return new Nodes.ArgumentsNode(loadFlags(), loadNodes(), startOffset, length); case 6: - return new Nodes.ArrayNode(loadNodes(), loadFlags(), startOffset, length); + return new Nodes.ArrayNode(loadFlags(), loadNodes(), startOffset, length); case 7: return new Nodes.ArrayPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), loadNodes(), startOffset, length); case 8: @@ -327,7 +327,7 @@ private Nodes.Node loadNode() { case 13: return new Nodes.BlockLocalVariableNode(loadConstant(), startOffset, length); case 14: - return new Nodes.BlockNode(loadConstants(), loadOptionalNode(), loadOptionalNode(), startOffset, length); + return new Nodes.BlockNode(loadConstants(), loadVarUInt(), loadOptionalNode(), loadOptionalNode(), startOffset, length); case 15: return new Nodes.BlockParameterNode(loadOptionalConstant(), startOffset, length); case 16: @@ -335,262 +335,266 @@ private Nodes.Node loadNode() { case 17: return new Nodes.BreakNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 18: - return new Nodes.CallAndWriteNode(loadOptionalNode(), loadFlags(), loadConstant(), loadConstant(), loadNode(), startOffset, length); + return new Nodes.CallAndWriteNode(loadFlags(), loadOptionalNode(), loadConstant(), loadConstant(), loadNode(), startOffset, length); case 19: - return new Nodes.CallNode(loadOptionalNode(), loadConstant(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.CallNode(loadFlags(), loadOptionalNode(), loadConstant(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 20: - return new Nodes.CallOperatorWriteNode(loadOptionalNode(), loadFlags(), loadConstant(), loadConstant(), loadConstant(), loadNode(), startOffset, length); + return new Nodes.CallOperatorWriteNode(loadFlags(), loadOptionalNode(), loadConstant(), loadConstant(), loadConstant(), loadNode(), startOffset, length); case 21: - return new Nodes.CallOrWriteNode(loadOptionalNode(), loadFlags(), loadConstant(), loadConstant(), loadNode(), startOffset, length); + return new Nodes.CallOrWriteNode(loadFlags(), loadOptionalNode(), loadConstant(), loadConstant(), loadNode(), startOffset, length); case 22: - return new Nodes.CapturePatternNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.CallTargetNode(loadFlags(), loadNode(), loadConstant(), startOffset, length); case 23: - return new Nodes.CaseMatchNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); + return new Nodes.CapturePatternNode(loadNode(), loadNode(), startOffset, length); case 24: - return new Nodes.CaseNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); + return new Nodes.CaseMatchNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); case 25: - return new Nodes.ClassNode(loadConstants(), loadNode(), loadOptionalNode(), loadOptionalNode(), loadConstant(), startOffset, length); + return new Nodes.CaseNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); case 26: - return new Nodes.ClassVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ClassNode(loadConstants(), loadNode(), loadOptionalNode(), loadOptionalNode(), loadConstant(), startOffset, length); case 27: - return new Nodes.ClassVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ClassVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 28: - return new Nodes.ClassVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ClassVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 29: - return new Nodes.ClassVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.ClassVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 30: - return new Nodes.ClassVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.ClassVariableReadNode(loadConstant(), startOffset, length); case 31: - return new Nodes.ClassVariableWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ClassVariableTargetNode(loadConstant(), startOffset, length); case 32: - return new Nodes.ConstantAndWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ClassVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 33: - return new Nodes.ConstantOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ConstantAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 34: - return new Nodes.ConstantOrWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ConstantOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 35: - return new Nodes.ConstantPathAndWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); + return new Nodes.ConstantOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 36: - return new Nodes.ConstantPathNode(loadOptionalNode(), loadNode(), startOffset, length); + return new Nodes.ConstantPathAndWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 37: - return new Nodes.ConstantPathOperatorWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ConstantPathNode(loadOptionalNode(), loadNode(), startOffset, length); case 38: - return new Nodes.ConstantPathOrWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); + return new Nodes.ConstantPathOperatorWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), loadConstant(), startOffset, length); case 39: - return new Nodes.ConstantPathTargetNode(loadOptionalNode(), loadNode(), startOffset, length); + return new Nodes.ConstantPathOrWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 40: - return new Nodes.ConstantPathWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); + return new Nodes.ConstantPathTargetNode(loadOptionalNode(), loadNode(), startOffset, length); case 41: - return new Nodes.ConstantReadNode(loadConstant(), startOffset, length); + return new Nodes.ConstantPathWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 42: - return new Nodes.ConstantTargetNode(loadConstant(), startOffset, length); + return new Nodes.ConstantReadNode(loadConstant(), startOffset, length); case 43: - return new Nodes.ConstantWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ConstantTargetNode(loadConstant(), startOffset, length); case 44: - return new Nodes.DefNode(buffer.getInt(), loadConstant(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), loadOptionalNode(), loadConstants(), startOffset, length); + return new Nodes.ConstantWriteNode(loadConstant(), loadNode(), startOffset, length); case 45: - return new Nodes.DefinedNode(loadNode(), startOffset, length); + return new Nodes.DefNode(buffer.getInt(), loadConstant(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), loadOptionalNode(), loadConstants(), loadVarUInt(), startOffset, length); case 46: - return new Nodes.ElseNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.DefinedNode(loadNode(), startOffset, length); case 47: - return new Nodes.EmbeddedStatementsNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.ElseNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 48: - return new Nodes.EmbeddedVariableNode(loadNode(), startOffset, length); + return new Nodes.EmbeddedStatementsNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 49: - return new Nodes.EnsureNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.EmbeddedVariableNode(loadNode(), startOffset, length); case 50: - return new Nodes.FalseNode(startOffset, length); + return new Nodes.EnsureNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 51: - return new Nodes.FindPatternNode(loadOptionalNode(), loadNode(), loadNodes(), loadNode(), startOffset, length); + return new Nodes.FalseNode(startOffset, length); case 52: - return new Nodes.FlipFlopNode(loadOptionalNode(), loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.FindPatternNode(loadOptionalNode(), loadNode(), loadNodes(), loadNode(), startOffset, length); case 53: - return new Nodes.FloatNode(startOffset, length); + return new Nodes.FlipFlopNode(loadFlags(), loadOptionalNode(), loadOptionalNode(), startOffset, length); case 54: - return new Nodes.ForNode(loadNode(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.FloatNode(startOffset, length); case 55: - return new Nodes.ForwardingArgumentsNode(startOffset, length); + return new Nodes.ForNode(loadNode(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 56: - return new Nodes.ForwardingParameterNode(startOffset, length); + return new Nodes.ForwardingArgumentsNode(startOffset, length); case 57: - return new Nodes.ForwardingSuperNode((Nodes.BlockNode) loadOptionalNode(), startOffset, length); + return new Nodes.ForwardingParameterNode(startOffset, length); case 58: - return new Nodes.GlobalVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.ForwardingSuperNode((Nodes.BlockNode) loadOptionalNode(), startOffset, length); case 59: - return new Nodes.GlobalVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.GlobalVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 60: - return new Nodes.GlobalVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.GlobalVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 61: - return new Nodes.GlobalVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.GlobalVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 62: - return new Nodes.GlobalVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.GlobalVariableReadNode(loadConstant(), startOffset, length); case 63: - return new Nodes.GlobalVariableWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.GlobalVariableTargetNode(loadConstant(), startOffset, length); case 64: - return new Nodes.HashNode(loadNodes(), startOffset, length); + return new Nodes.GlobalVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 65: - return new Nodes.HashPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), startOffset, length); + return new Nodes.HashNode(loadNodes(), startOffset, length); case 66: - return new Nodes.IfNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); + return new Nodes.HashPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), startOffset, length); case 67: - return new Nodes.ImaginaryNode(loadNode(), startOffset, length); + return new Nodes.IfNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 68: - return new Nodes.ImplicitNode(loadNode(), startOffset, length); + return new Nodes.ImaginaryNode(loadNode(), startOffset, length); case 69: - return new Nodes.ImplicitRestNode(startOffset, length); + return new Nodes.ImplicitNode(loadNode(), startOffset, length); case 70: - return new Nodes.InNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.ImplicitRestNode(startOffset, length); case 71: - return new Nodes.IndexAndWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadFlags(), loadNode(), startOffset, length); + return new Nodes.InNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 72: - return new Nodes.IndexOperatorWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadFlags(), loadConstant(), loadNode(), startOffset, length); + return new Nodes.IndexAndWriteNode(loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadNode(), startOffset, length); case 73: - return new Nodes.IndexOrWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadFlags(), loadNode(), startOffset, length); + return new Nodes.IndexOperatorWriteNode(loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadConstant(), loadNode(), startOffset, length); case 74: - return new Nodes.InstanceVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.IndexOrWriteNode(loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadNode(), startOffset, length); case 75: - return new Nodes.InstanceVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.IndexTargetNode(loadFlags(), loadNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 76: - return new Nodes.InstanceVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.InstanceVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 77: - return new Nodes.InstanceVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.InstanceVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 78: - return new Nodes.InstanceVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.InstanceVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 79: - return new Nodes.InstanceVariableWriteNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.InstanceVariableReadNode(loadConstant(), startOffset, length); case 80: - return new Nodes.IntegerNode(loadFlags(), startOffset, length); + return new Nodes.InstanceVariableTargetNode(loadConstant(), startOffset, length); case 81: - return new Nodes.InterpolatedMatchLastLineNode(loadNodes(), loadFlags(), startOffset, length); + return new Nodes.InstanceVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 82: - return new Nodes.InterpolatedRegularExpressionNode(loadNodes(), loadFlags(), startOffset, length); + return new Nodes.IntegerNode(loadFlags(), startOffset, length); case 83: - return new Nodes.InterpolatedStringNode(loadNodes(), startOffset, length); + return new Nodes.InterpolatedMatchLastLineNode(loadFlags(), loadNodes(), startOffset, length); case 84: - return new Nodes.InterpolatedSymbolNode(loadNodes(), startOffset, length); + return new Nodes.InterpolatedRegularExpressionNode(loadFlags(), loadNodes(), startOffset, length); case 85: - return new Nodes.InterpolatedXStringNode(loadNodes(), startOffset, length); + return new Nodes.InterpolatedStringNode(loadNodes(), startOffset, length); case 86: - return new Nodes.KeywordHashNode(loadNodes(), startOffset, length); + return new Nodes.InterpolatedSymbolNode(loadNodes(), startOffset, length); case 87: - return new Nodes.KeywordRestParameterNode(loadOptionalConstant(), startOffset, length); + return new Nodes.InterpolatedXStringNode(loadNodes(), startOffset, length); case 88: - return new Nodes.LambdaNode(loadConstants(), loadOptionalNode(), loadOptionalNode(), startOffset, length); + return new Nodes.KeywordHashNode(loadFlags(), loadNodes(), startOffset, length); case 89: - return new Nodes.LocalVariableAndWriteNode(loadNode(), loadConstant(), loadVarUInt(), startOffset, length); + return new Nodes.KeywordRestParameterNode(loadOptionalConstant(), startOffset, length); case 90: - return new Nodes.LocalVariableOperatorWriteNode(loadNode(), loadConstant(), loadConstant(), loadVarUInt(), startOffset, length); + return new Nodes.LambdaNode(loadConstants(), loadVarUInt(), loadOptionalNode(), loadOptionalNode(), startOffset, length); case 91: - return new Nodes.LocalVariableOrWriteNode(loadNode(), loadConstant(), loadVarUInt(), startOffset, length); + return new Nodes.LocalVariableAndWriteNode(loadNode(), loadConstant(), loadVarUInt(), startOffset, length); case 92: - return new Nodes.LocalVariableReadNode(loadConstant(), loadVarUInt(), startOffset, length); + return new Nodes.LocalVariableOperatorWriteNode(loadNode(), loadConstant(), loadConstant(), loadVarUInt(), startOffset, length); case 93: - return new Nodes.LocalVariableTargetNode(loadConstant(), loadVarUInt(), startOffset, length); + return new Nodes.LocalVariableOrWriteNode(loadNode(), loadConstant(), loadVarUInt(), startOffset, length); case 94: - return new Nodes.LocalVariableWriteNode(loadConstant(), loadVarUInt(), loadNode(), startOffset, length); + return new Nodes.LocalVariableReadNode(loadConstant(), loadVarUInt(), startOffset, length); case 95: - return new Nodes.MatchLastLineNode(loadString(), loadFlags(), startOffset, length); + return new Nodes.LocalVariableTargetNode(loadConstant(), loadVarUInt(), startOffset, length); case 96: - return new Nodes.MatchPredicateNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.LocalVariableWriteNode(loadConstant(), loadVarUInt(), loadNode(), startOffset, length); case 97: - return new Nodes.MatchRequiredNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.MatchLastLineNode(loadFlags(), loadString(), startOffset, length); case 98: - return new Nodes.MatchWriteNode((Nodes.CallNode) loadNode(), loadNodes(), startOffset, length); + return new Nodes.MatchPredicateNode(loadNode(), loadNode(), startOffset, length); case 99: - return new Nodes.MissingNode(startOffset, length); + return new Nodes.MatchRequiredNode(loadNode(), loadNode(), startOffset, length); case 100: - return new Nodes.ModuleNode(loadConstants(), loadNode(), loadOptionalNode(), loadConstant(), startOffset, length); + return new Nodes.MatchWriteNode((Nodes.CallNode) loadNode(), loadNodes(), startOffset, length); case 101: - return new Nodes.MultiTargetNode(loadNodes(), loadOptionalNode(), loadNodes(), startOffset, length); + return new Nodes.MissingNode(startOffset, length); case 102: - return new Nodes.MultiWriteNode(loadNodes(), loadOptionalNode(), loadNodes(), loadNode(), startOffset, length); + return new Nodes.ModuleNode(loadConstants(), loadNode(), loadOptionalNode(), loadConstant(), startOffset, length); case 103: - return new Nodes.NextNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); + return new Nodes.MultiTargetNode(loadNodes(), loadOptionalNode(), loadNodes(), startOffset, length); case 104: - return new Nodes.NilNode(startOffset, length); + return new Nodes.MultiWriteNode(loadNodes(), loadOptionalNode(), loadNodes(), loadNode(), startOffset, length); case 105: - return new Nodes.NoKeywordsParameterNode(startOffset, length); + return new Nodes.NextNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 106: - return new Nodes.NumberedParametersNode(buffer.get(), startOffset, length); + return new Nodes.NilNode(startOffset, length); case 107: - return new Nodes.NumberedReferenceReadNode(loadVarUInt(), startOffset, length); + return new Nodes.NoKeywordsParameterNode(startOffset, length); case 108: - return new Nodes.OptionalKeywordParameterNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.NumberedParametersNode(buffer.get(), startOffset, length); case 109: - return new Nodes.OptionalParameterNode(loadConstant(), loadNode(), startOffset, length); + return new Nodes.NumberedReferenceReadNode(loadVarUInt(), startOffset, length); case 110: - return new Nodes.OrNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.OptionalKeywordParameterNode(loadConstant(), loadNode(), startOffset, length); case 111: - return new Nodes.ParametersNode(loadNodes(), loadNodes(), loadOptionalNode(), loadNodes(), loadNodes(), loadOptionalNode(), (Nodes.BlockParameterNode) loadOptionalNode(), startOffset, length); + return new Nodes.OptionalParameterNode(loadConstant(), loadNode(), startOffset, length); case 112: - return new Nodes.ParenthesesNode(loadOptionalNode(), startOffset, length); + return new Nodes.OrNode(loadNode(), loadNode(), startOffset, length); case 113: - return new Nodes.PinnedExpressionNode(loadNode(), startOffset, length); + return new Nodes.ParametersNode(loadNodes(), loadNodes(), loadOptionalNode(), loadNodes(), loadNodes(), loadOptionalNode(), (Nodes.BlockParameterNode) loadOptionalNode(), startOffset, length); case 114: - return new Nodes.PinnedVariableNode(loadNode(), startOffset, length); + return new Nodes.ParenthesesNode(loadOptionalNode(), startOffset, length); case 115: - return new Nodes.PostExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.PinnedExpressionNode(loadNode(), startOffset, length); case 116: - return new Nodes.PreExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.PinnedVariableNode(loadNode(), startOffset, length); case 117: - return new Nodes.ProgramNode(loadConstants(), (Nodes.StatementsNode) loadNode(), startOffset, length); + return new Nodes.PostExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 118: - return new Nodes.RangeNode(loadOptionalNode(), loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.PreExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 119: - return new Nodes.RationalNode(loadNode(), startOffset, length); + return new Nodes.ProgramNode(loadConstants(), (Nodes.StatementsNode) loadNode(), startOffset, length); case 120: - return new Nodes.RedoNode(startOffset, length); + return new Nodes.RangeNode(loadFlags(), loadOptionalNode(), loadOptionalNode(), startOffset, length); case 121: - return new Nodes.RegularExpressionNode(loadString(), loadFlags(), startOffset, length); + return new Nodes.RationalNode(loadNode(), startOffset, length); case 122: - return new Nodes.RequiredKeywordParameterNode(loadConstant(), startOffset, length); + return new Nodes.RedoNode(startOffset, length); case 123: - return new Nodes.RequiredParameterNode(loadConstant(), startOffset, length); + return new Nodes.RegularExpressionNode(loadFlags(), loadString(), startOffset, length); case 124: - return new Nodes.RescueModifierNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.RequiredKeywordParameterNode(loadConstant(), startOffset, length); case 125: - return new Nodes.RescueNode(loadNodes(), loadOptionalNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), startOffset, length); + return new Nodes.RequiredParameterNode(loadConstant(), startOffset, length); case 126: - return new Nodes.RestParameterNode(loadOptionalConstant(), startOffset, length); + return new Nodes.RescueModifierNode(loadNode(), loadNode(), startOffset, length); case 127: - return new Nodes.RetryNode(startOffset, length); + return new Nodes.RescueNode(loadNodes(), loadOptionalNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), startOffset, length); case 128: - return new Nodes.ReturnNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); + return new Nodes.RestParameterNode(loadOptionalConstant(), startOffset, length); case 129: - return new Nodes.SelfNode(startOffset, length); + return new Nodes.RetryNode(startOffset, length); case 130: - return new Nodes.SingletonClassNode(loadConstants(), loadNode(), loadOptionalNode(), startOffset, length); + return new Nodes.ReturnNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 131: - return new Nodes.SourceEncodingNode(startOffset, length); + return new Nodes.SelfNode(startOffset, length); case 132: - return new Nodes.SourceFileNode(loadString(), startOffset, length); + return new Nodes.SingletonClassNode(loadConstants(), loadNode(), loadOptionalNode(), startOffset, length); case 133: - return new Nodes.SourceLineNode(startOffset, length); + return new Nodes.SourceEncodingNode(startOffset, length); case 134: - return new Nodes.SplatNode(loadOptionalNode(), startOffset, length); + return new Nodes.SourceFileNode(loadString(), startOffset, length); case 135: - return new Nodes.StatementsNode(loadNodes(), startOffset, length); + return new Nodes.SourceLineNode(startOffset, length); case 136: - return new Nodes.StringNode(loadFlags(), loadString(), startOffset, length); + return new Nodes.SplatNode(loadOptionalNode(), startOffset, length); case 137: - return new Nodes.SuperNode((Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); + return new Nodes.StatementsNode(loadNodes(), startOffset, length); case 138: - return new Nodes.SymbolNode(loadString(), startOffset, length); + return new Nodes.StringNode(loadFlags(), loadString(), startOffset, length); case 139: - return new Nodes.TrueNode(startOffset, length); + return new Nodes.SuperNode((Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 140: - return new Nodes.UndefNode(loadNodes(), startOffset, length); + return new Nodes.SymbolNode(loadFlags(), loadString(), startOffset, length); case 141: - return new Nodes.UnlessNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); + return new Nodes.TrueNode(startOffset, length); case 142: - return new Nodes.UntilNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.UndefNode(loadNodes(), startOffset, length); case 143: - return new Nodes.WhenNode(loadNodes(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.UnlessNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); case 144: - return new Nodes.WhileNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.UntilNode(loadFlags(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 145: - return new Nodes.XStringNode(loadString(), startOffset, length); + return new Nodes.WhenNode(loadNodes(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 146: + return new Nodes.WhileNode(loadFlags(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + case 147: + return new Nodes.XStringNode(loadFlags(), loadString(), startOffset, length); + case 148: return new Nodes.YieldNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); default: throw new Error("Unknown node type: " + type); diff --git a/src/yarp/java/org/prism/Nodes.java b/src/yarp/java/org/prism/Nodes.java index 49b034f00b92..b658aa8750b9 100644 --- a/src/yarp/java/org/prism/Nodes.java +++ b/src/yarp/java/org/prism/Nodes.java @@ -10,6 +10,10 @@ import java.lang.Override; import java.lang.String; import java.lang.StringBuilder; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -18,9 +22,13 @@ // @formatter:off public abstract class Nodes { - public static final byte[][] EMPTY_BYTE_ARRAY_ARRAY = {}; public static final String[] EMPTY_STRING_ARRAY = {}; + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.SOURCE) + public @interface Nullable { + } + public static final class Location { public static final Location[] EMPTY_ARRAY = {}; @@ -243,6 +251,12 @@ public static final class CallNodeFlags implements Comparable { // a call that could have been a local variable public static final short VARIABLE_CALL = 1 << 1; + // a call that is an attribute write, so the value being written should be returned + public static final short ATTRIBUTE_WRITE = 1 << 2; + + // a call that ignores method visibility + public static final short IGNORE_VISIBILITY = 1 << 3; + public static boolean isSafeNavigation(short flags) { return (flags & SAFE_NAVIGATION) != 0; } @@ -251,6 +265,14 @@ public static boolean isVariableCall(short flags) { return (flags & VARIABLE_CALL) != 0; } + public static boolean isAttributeWrite(short flags) { + return (flags & ATTRIBUTE_WRITE) != 0; + } + + public static boolean isIgnoreVisibility(short flags) { + return (flags & IGNORE_VISIBILITY) != 0; + } + private final short flags; public CallNodeFlags(short flags) { @@ -284,6 +306,68 @@ public boolean isVariableCall() { return (flags & VARIABLE_CALL) != 0; } + public boolean isAttributeWrite() { + return (flags & ATTRIBUTE_WRITE) != 0; + } + + public boolean isIgnoreVisibility() { + return (flags & IGNORE_VISIBILITY) != 0; + } + + } + + /** + * Flags for nodes that have unescaped content. + */ + public static final class EncodingFlags implements Comparable { + + // internal bytes forced the encoding to UTF-8 + public static final short FORCED_UTF8_ENCODING = 1 << 0; + + // internal bytes forced the encoding to binary + public static final short FORCED_BINARY_ENCODING = 1 << 1; + + public static boolean isForcedUtf8Encoding(short flags) { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public static boolean isForcedBinaryEncoding(short flags) { + return (flags & FORCED_BINARY_ENCODING) != 0; + } + + private final short flags; + + public EncodingFlags(short flags) { + this.flags = flags; + } + + @Override + public int hashCode() { + return flags; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof EncodingFlags)) { + return false; + } + + return flags == ((EncodingFlags) other).flags; + } + + @Override + public int compareTo(EncodingFlags other) { + return flags - other.flags; + } + + public boolean isForcedUtf8Encoding() { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public boolean isForcedBinaryEncoding() { + return (flags & FORCED_BINARY_ENCODING) != 0; + } + } /** @@ -294,11 +378,11 @@ public static final class IntegerBaseFlags implements Comparable { + + // a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments + public static final short SYMBOL_KEYS = 1 << 0; + + public static boolean isSymbolKeys(short flags) { + return (flags & SYMBOL_KEYS) != 0; + } + + private final short flags; + + public KeywordHashNodeFlags(short flags) { + this.flags = flags; + } + + @Override + public int hashCode() { + return flags; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof KeywordHashNodeFlags)) { + return false; + } + + return flags == ((KeywordHashNodeFlags) other).flags; + } + + @Override + public int compareTo(KeywordHashNodeFlags other) { + return flags - other.flags; + } + + public boolean isSymbolKeys() { + return (flags & SYMBOL_KEYS) != 0; + } + + } + /** * Flags for while and until loop nodes. */ @@ -477,6 +604,15 @@ public static final class RegularExpressionFlags implements Comparable { + // internal bytes forced the encoding to UTF-8 + public static final short FORCED_UTF8_ENCODING = 1 << 0; + + // internal bytes forced the encoding to binary + public static final short FORCED_BINARY_ENCODING = 1 << 1; + // frozen by virtue of a `frozen_string_literal` comment - public static final short FROZEN = 1 << 0; + public static final short FROZEN = 1 << 2; + + public static boolean isForcedUtf8Encoding(short flags) { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public static boolean isForcedBinaryEncoding(short flags) { + return (flags & FORCED_BINARY_ENCODING) != 0; + } public static boolean isFrozen(short flags) { return (flags & FROZEN) != 0; @@ -605,12 +779,85 @@ public int compareTo(StringFlags other) { return flags - other.flags; } + public boolean isForcedUtf8Encoding() { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public boolean isForcedBinaryEncoding() { + return (flags & FORCED_BINARY_ENCODING) != 0; + } + public boolean isFrozen() { return (flags & FROZEN) != 0; } } + /** + * Flags for symbol nodes. + */ + public static final class SymbolFlags implements Comparable { + + // internal bytes forced the encoding to UTF-8 + public static final short FORCED_UTF8_ENCODING = 1 << 0; + + // internal bytes forced the encoding to binary + public static final short FORCED_BINARY_ENCODING = 1 << 1; + + // internal bytes forced the encoding to US-ASCII + public static final short FORCED_US_ASCII_ENCODING = 1 << 2; + + public static boolean isForcedUtf8Encoding(short flags) { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public static boolean isForcedBinaryEncoding(short flags) { + return (flags & FORCED_BINARY_ENCODING) != 0; + } + + public static boolean isForcedUsAsciiEncoding(short flags) { + return (flags & FORCED_US_ASCII_ENCODING) != 0; + } + + private final short flags; + + public SymbolFlags(short flags) { + this.flags = flags; + } + + @Override + public int hashCode() { + return flags; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof SymbolFlags)) { + return false; + } + + return flags == ((SymbolFlags) other).flags; + } + + @Override + public int compareTo(SymbolFlags other) { + return flags - other.flags; + } + + public boolean isForcedUtf8Encoding() { + return (flags & FORCED_UTF8_ENCODING) != 0; + } + + public boolean isForcedBinaryEncoding() { + return (flags & FORCED_BINARY_ENCODING) != 0; + } + + public boolean isForcedUsAsciiEncoding() { + return (flags & FORCED_US_ASCII_ENCODING) != 0; + } + + } + /** * Represents the use of the `alias` keyword to alias a global variable. * @@ -810,13 +1057,13 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^ */ public static final class ArgumentsNode extends Node { - public final Node[] arguments; public final short flags; + public final Node[] arguments; - public ArgumentsNode(Node[] arguments, short flags, int startOffset, int length) { + public ArgumentsNode(short flags, Node[] arguments, int startOffset, int length) { super(startOffset, length); - this.arguments = arguments; this.flags = flags; + this.arguments = arguments; } public boolean isContainsKeywordSplat() { @@ -848,15 +1095,15 @@ protected String toString(String indent) { String nextIndent = indent + " "; String nextNextIndent = nextIndent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("arguments: "); builder.append('\n'); for (Node child : this.arguments) { builder.append(nextNextIndent).append(child.toString(nextNextIndent)); } - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -869,13 +1116,13 @@ protected String toString(String indent) { * ^^^^^^^^^ */ public static final class ArrayNode extends Node { - public final Node[] elements; public final short flags; + public final Node[] elements; - public ArrayNode(Node[] elements, short flags, int startOffset, int length) { + public ArrayNode(short flags, Node[] elements, int startOffset, int length) { super(startOffset, length); - this.elements = elements; this.flags = flags; + this.elements = elements; } public boolean isContainsSplat() { @@ -907,15 +1154,15 @@ protected String toString(String indent) { String nextIndent = indent + " "; String nextNextIndent = nextIndent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("elements: "); builder.append('\n'); for (Node child : this.elements) { builder.append(nextNextIndent).append(child.toString(nextNextIndent)); } - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -939,10 +1186,10 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^ */ public static final class ArrayPatternNode extends Node { - /** optional (can be null) */ + @Nullable public final Node constant; public final Node[] requireds; - /** optional (can be null) */ + @Nullable public final Node rest; public final Node[] posts; @@ -1022,7 +1269,7 @@ protected String toString(String indent) { */ public static final class AssocNode extends Node { public final Node key; - /** optional (can be null) */ + @Nullable public final Node value; public AssocNode(Node key, Node value, int startOffset, int length) { @@ -1072,7 +1319,7 @@ protected String toString(String indent) { * ^^^^^ */ public static final class AssocSplatNode extends Node { - /** optional (can be null) */ + @Nullable public final Node value; public AssocSplatNode(Node value, int startOffset, int length) { @@ -1161,13 +1408,13 @@ protected String toString(String indent) { * ^^^^^ */ public static final class BeginNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - /** optional (can be null) */ + @Nullable public final RescueNode rescue_clause; - /** optional (can be null) */ + @Nullable public final ElseNode else_clause; - /** optional (can be null) */ + @Nullable public final EnsureNode ensure_clause; public BeginNode(StatementsNode statements, RescueNode rescue_clause, ElseNode else_clause, EnsureNode ensure_clause, int startOffset, int length) { @@ -1238,7 +1485,7 @@ protected String toString(String indent) { * ^^^^^^^^^^ */ public static final class BlockArgumentNode extends Node { - /** optional (can be null) */ + @Nullable public final Node expression; public BlockArgumentNode(Node expression, int startOffset, int length) { @@ -1326,14 +1573,16 @@ protected String toString(String indent) { */ public static final class BlockNode extends Node { public final String[] locals; - /** optional (can be null) */ + public final int locals_body_index; + @Nullable public final Node parameters; - /** optional (can be null) */ + @Nullable public final Node body; - public BlockNode(String[] locals, Node parameters, Node body, int startOffset, int length) { + public BlockNode(String[] locals, int locals_body_index, Node parameters, Node body, int startOffset, int length) { super(startOffset, length); this.locals = locals; + this.locals_body_index = locals_body_index; this.parameters = parameters; this.body = body; } @@ -1372,6 +1621,10 @@ protected String toString(String indent) { builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); } builder.append(nextIndent); + builder.append("locals_body_index: "); + builder.append(this.locals_body_index); + builder.append('\n'); + builder.append(nextIndent); builder.append("parameters: "); builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); builder.append(nextIndent); @@ -1389,7 +1642,7 @@ protected String toString(String indent) { * end */ public static final class BlockParameterNode extends Node { - /** optional (can be null) */ + @Nullable public final String name; public BlockParameterNode(String name, int startOffset, int length) { @@ -1436,7 +1689,7 @@ protected String toString(String indent) { * end */ public static final class BlockParametersNode extends Node { - /** optional (can be null) */ + @Nullable public final ParametersNode parameters; public final Node[] locals; @@ -1496,7 +1749,7 @@ protected String toString(String indent) { * ^^^^^^^^^ */ public static final class BreakNode extends Node { - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; public BreakNode(ArgumentsNode arguments, int startOffset, int length) { @@ -1541,17 +1794,17 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^ */ public static final class CallAndWriteNode extends Node { - /** optional (can be null) */ - public final Node receiver; public final short flags; + @Nullable + public final Node receiver; public final String read_name; public final String write_name; public final Node value; - public CallAndWriteNode(Node receiver, short flags, String read_name, String write_name, Node value, int startOffset, int length) { + public CallAndWriteNode(short flags, Node receiver, String read_name, String write_name, Node value, int startOffset, int length) { super(startOffset, length); - this.receiver = receiver; this.flags = flags; + this.receiver = receiver; this.read_name = read_name; this.write_name = write_name; this.value = value; @@ -1564,6 +1817,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -1590,13 +1851,13 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); - builder.append("receiver: "); - builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); - builder.append(nextIndent); builder.append("flags: "); builder.append(this.flags); builder.append('\n'); builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); builder.append("read_name: "); builder.append('"').append(this.read_name).append('"'); builder.append('\n'); @@ -1633,22 +1894,38 @@ protected String toString(String indent) { * ^^^^^^^^ */ public static final class CallNode extends Node { - /** optional (can be null) */ + public final short flags; + /** + *
+         * The object that the method is being called on. This can be either
+         * `nil` or a node representing any kind of expression that returns a
+         * non-void value.
+         *
+         *     foo.bar
+         *     ^^^
+         *
+         *     +foo
+         *      ^^^
+         *
+         *     foo + bar
+         *     ^^^
+         * 
+ */ + @Nullable public final Node receiver; public final String name; - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; - /** optional (can be null) */ + @Nullable public final Node block; - public final short flags; - public CallNode(Node receiver, String name, ArgumentsNode arguments, Node block, short flags, int startOffset, int length) { + public CallNode(short flags, Node receiver, String name, ArgumentsNode arguments, Node block, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.receiver = receiver; this.name = name; this.arguments = arguments; this.block = block; - this.flags = flags; } public boolean isSafeNavigation() { @@ -1658,6 +1935,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -1689,6 +1974,10 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("receiver: "); builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); builder.append(nextIndent); @@ -1701,10 +1990,6 @@ protected String toString(String indent) { builder.append(nextIndent); builder.append("block: "); builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -1716,18 +2001,18 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^ */ public static final class CallOperatorWriteNode extends Node { - /** optional (can be null) */ - public final Node receiver; public final short flags; + @Nullable + public final Node receiver; public final String read_name; public final String write_name; public final String operator; public final Node value; - public CallOperatorWriteNode(Node receiver, short flags, String read_name, String write_name, String operator, Node value, int startOffset, int length) { + public CallOperatorWriteNode(short flags, Node receiver, String read_name, String write_name, String operator, Node value, int startOffset, int length) { super(startOffset, length); - this.receiver = receiver; this.flags = flags; + this.receiver = receiver; this.read_name = read_name; this.write_name = write_name; this.operator = operator; @@ -1741,6 +2026,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -1767,13 +2060,13 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); - builder.append("receiver: "); - builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); - builder.append(nextIndent); builder.append("flags: "); builder.append(this.flags); builder.append('\n'); builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); builder.append("read_name: "); builder.append('"').append(this.read_name).append('"'); builder.append('\n'); @@ -1799,17 +2092,17 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^ */ public static final class CallOrWriteNode extends Node { - /** optional (can be null) */ - public final Node receiver; public final short flags; + @Nullable + public final Node receiver; public final String read_name; public final String write_name; public final Node value; - public CallOrWriteNode(Node receiver, short flags, String read_name, String write_name, Node value, int startOffset, int length) { + public CallOrWriteNode(short flags, Node receiver, String read_name, String write_name, Node value, int startOffset, int length) { super(startOffset, length); - this.receiver = receiver; this.flags = flags; + this.receiver = receiver; this.read_name = read_name; this.write_name = write_name; this.value = value; @@ -1822,6 +2115,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -1848,13 +2149,13 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); - builder.append("receiver: "); - builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); - builder.append(nextIndent); builder.append("flags: "); builder.append(this.flags); builder.append('\n'); builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); builder.append("read_name: "); builder.append('"').append(this.read_name).append('"'); builder.append('\n'); @@ -1869,6 +2170,84 @@ protected String toString(String indent) { } } + /** + * Represents assigning to a method call. + * + * foo.bar, = 1 + * ^^^^^^^ + * + * begin + * rescue => foo.bar + * ^^^^^^^ + * end + * + * for foo.bar in baz do end + * ^^^^^^^ + */ + public static final class CallTargetNode extends Node { + public final short flags; + public final Node receiver; + public final String name; + + public CallTargetNode(short flags, Node receiver, String name, int startOffset, int length) { + super(startOffset, length); + this.flags = flags; + this.receiver = receiver; + this.name = name; + } + + public boolean isSafeNavigation() { + return CallNodeFlags.isSafeNavigation(this.flags); + } + + public boolean isVariableCall() { + return CallNodeFlags.isVariableCall(this.flags); + } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + this.receiver.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.receiver }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitCallTargetNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } + } + /** * Represents assigning to a local variable in pattern matching. * @@ -1926,10 +2305,10 @@ protected String toString(String indent) { * ^^^^^^^^^ */ public static final class CaseMatchNode extends Node { - /** optional (can be null) */ + @Nullable public final Node predicate; public final Node[] conditions; - /** optional (can be null) */ + @Nullable public final ElseNode consequent; public CaseMatchNode(Node predicate, Node[] conditions, ElseNode consequent, int startOffset, int length) { @@ -1998,10 +2377,10 @@ protected String toString(String indent) { * ^^^^^^^^^^ */ public static final class CaseNode extends Node { - /** optional (can be null) */ + @Nullable public final Node predicate; public final Node[] conditions; - /** optional (can be null) */ + @Nullable public final ElseNode consequent; public CaseNode(Node predicate, Node[] conditions, ElseNode consequent, int startOffset, int length) { @@ -2070,9 +2449,9 @@ protected String toString(String indent) { public static final class ClassNode extends Node { public final String[] locals; public final Node constant_path; - /** optional (can be null) */ + @Nullable public final Node superclass; - /** optional (can be null) */ + @Nullable public final Node body; public final String name; @@ -2623,7 +3002,7 @@ protected String toString(String indent) { * ^^^^^^^^ */ public static final class ConstantPathNode extends Node { - /** optional (can be null) */ + @Nullable public final Node parent; public final Node child; @@ -2776,7 +3155,7 @@ protected String toString(String indent) { * ^^^^^^^^ ^^^^^^^^ */ public static final class ConstantPathTargetNode extends Node { - /** optional (can be null) */ + @Nullable public final Node parent; public final Node child; @@ -3016,15 +3395,16 @@ protected String toString(String indent) { public static final class DefNode extends Node { public final int serializedLength; public final String name; - /** optional (can be null) */ + @Nullable public final Node receiver; - /** optional (can be null) */ + @Nullable public final ParametersNode parameters; - /** optional (can be null) */ + @Nullable public final Node body; public final String[] locals; + public final int locals_body_index; - public DefNode(int serializedLength, String name, Node receiver, ParametersNode parameters, Node body, String[] locals, int startOffset, int length) { + public DefNode(int serializedLength, String name, Node receiver, ParametersNode parameters, Node body, String[] locals, int locals_body_index, int startOffset, int length) { super(startOffset, length); this.serializedLength = serializedLength; this.name = name; @@ -3032,6 +3412,7 @@ public DefNode(int serializedLength, String name, Node receiver, ParametersNode this.parameters = parameters; this.body = body; this.locals = locals; + this.locals_body_index = locals_body_index; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3083,6 +3464,10 @@ protected String toString(String indent) { for (String constant : this.locals) { builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); } + builder.append(nextIndent); + builder.append("locals_body_index: "); + builder.append(this.locals_body_index); + builder.append('\n'); return builder.toString(); } } @@ -3136,7 +3521,7 @@ protected String toString(String indent) { * ^^^^^^^^^^ */ public static final class ElseNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public ElseNode(StatementsNode statements, int startOffset, int length) { @@ -3181,7 +3566,7 @@ protected String toString(String indent) { * ^^^^^^ */ public static final class EmbeddedStatementsNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public EmbeddedStatementsNode(StatementsNode statements, int startOffset, int length) { @@ -3272,7 +3657,7 @@ protected String toString(String indent) { * end */ public static final class EnsureNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public EnsureNode(StatementsNode statements, int startOffset, int length) { @@ -3359,7 +3744,7 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^^ */ public static final class FindPatternNode extends Node { - /** optional (can be null) */ + @Nullable public final Node constant; public final Node left; public final Node[] requireds; @@ -3433,17 +3818,17 @@ protected String toString(String indent) { * ^^^^^^^^^^ */ public static final class FlipFlopNode extends Node { - /** optional (can be null) */ + public final short flags; + @Nullable public final Node left; - /** optional (can be null) */ + @Nullable public final Node right; - public final short flags; - public FlipFlopNode(Node left, Node right, short flags, int startOffset, int length) { + public FlipFlopNode(short flags, Node left, Node right, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.left = left; this.right = right; - this.flags = flags; } public boolean isExcludeEnd() { @@ -3477,15 +3862,15 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("left: "); builder.append(this.left == null ? "null\n" : this.left.toString(nextIndent)); builder.append(nextIndent); builder.append("right: "); builder.append(this.right == null ? "null\n" : this.right.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -3535,7 +3920,7 @@ protected String toString(String indent) { public static final class ForNode extends Node { public final Node index; public final Node collection; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public ForNode(Node index, Node collection, StatementsNode statements, int startOffset, int length) { @@ -3665,7 +4050,7 @@ protected String toString(String indent) { * ^^^^^ */ public static final class ForwardingSuperNode extends Node { - /** optional (can be null) */ + @Nullable public final BlockNode block; public ForwardingSuperNode(BlockNode block, int startOffset, int length) { @@ -4043,10 +4428,10 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^ */ public static final class HashPatternNode extends Node { - /** optional (can be null) */ + @Nullable public final Node constant; public final Node[] elements; - /** optional (can be null) */ + @Nullable public final Node rest; public HashPatternNode(Node constant, Node[] elements, Node rest, int startOffset, int length) { @@ -4117,9 +4502,9 @@ protected String toString(String indent) { */ public static final class IfNode extends Node { public final Node predicate; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - /** optional (can be null) */ + @Nullable public final Node consequent; public IfNode(Node predicate, StatementsNode statements, Node consequent, int startOffset, int length) { @@ -4315,7 +4700,7 @@ protected String toString(String indent) { */ public static final class InNode extends Node { public final Node pattern; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public InNode(Node pattern, StatementsNode statements, int startOffset, int length) { @@ -4359,27 +4744,120 @@ protected String toString(String indent) { } /** - * Represents the use of the `&&=` operator on a call to the `[]` method. + * Represents the use of the `&&=` operator on a call to the `[]` method. + * + * foo.bar[baz] &&= value + * ^^^^^^^^^^^^^^^^^^^^^^ + */ + public static final class IndexAndWriteNode extends Node { + public final short flags; + @Nullable + public final Node receiver; + @Nullable + public final ArgumentsNode arguments; + @Nullable + public final Node block; + public final Node value; + + public IndexAndWriteNode(short flags, Node receiver, ArgumentsNode arguments, Node block, Node value, int startOffset, int length) { + super(startOffset, length); + this.flags = flags; + this.receiver = receiver; + this.arguments = arguments; + this.block = block; + this.value = value; + } + + public boolean isSafeNavigation() { + return CallNodeFlags.isSafeNavigation(this.flags); + } + + public boolean isVariableCall() { + return CallNodeFlags.isVariableCall(this.flags); + } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + if (this.receiver != null) { + this.receiver.accept(visitor); + } + if (this.arguments != null) { + this.arguments.accept(visitor); + } + if (this.block != null) { + this.block.accept(visitor); + } + this.value.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.receiver, this.arguments, this.block, this.value }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitIndexAndWriteNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("block: "); + builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } + } + + /** + * Represents the use of an assignment operator on a call to `[]`. * - * foo.bar[baz] &&= value - * ^^^^^^^^^^^^^^^^^^^^^^ + * foo.bar[baz] += value + * ^^^^^^^^^^^^^^^^^^^^^ */ - public static final class IndexAndWriteNode extends Node { - /** optional (can be null) */ + public static final class IndexOperatorWriteNode extends Node { + public final short flags; + @Nullable public final Node receiver; - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; - /** optional (can be null) */ + @Nullable public final Node block; - public final short flags; + public final String operator; public final Node value; - public IndexAndWriteNode(Node receiver, ArgumentsNode arguments, Node block, short flags, Node value, int startOffset, int length) { + public IndexOperatorWriteNode(short flags, Node receiver, ArgumentsNode arguments, Node block, String operator, Node value, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.receiver = receiver; this.arguments = arguments; this.block = block; - this.flags = flags; + this.operator = operator; this.value = value; } @@ -4390,6 +4868,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -4409,7 +4895,7 @@ public Node[] childNodes() { } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitIndexAndWriteNode(this); + return visitor.visitIndexOperatorWriteNode(this); } @Override @@ -4422,6 +4908,10 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("receiver: "); builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); builder.append(nextIndent); @@ -4431,8 +4921,8 @@ protected String toString(String indent) { builder.append("block: "); builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); builder.append('\n'); builder.append(nextIndent); builder.append("value: "); @@ -4442,29 +4932,27 @@ protected String toString(String indent) { } /** - * Represents the use of an assignment operator on a call to `[]`. + * Represents the use of the `||=` operator on a call to `[]`. * - * foo.bar[baz] += value - * ^^^^^^^^^^^^^^^^^^^^^ + * foo.bar[baz] ||= value + * ^^^^^^^^^^^^^^^^^^^^^^ */ - public static final class IndexOperatorWriteNode extends Node { - /** optional (can be null) */ + public static final class IndexOrWriteNode extends Node { + public final short flags; + @Nullable public final Node receiver; - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; - /** optional (can be null) */ + @Nullable public final Node block; - public final short flags; - public final String operator; public final Node value; - public IndexOperatorWriteNode(Node receiver, ArgumentsNode arguments, Node block, short flags, String operator, Node value, int startOffset, int length) { + public IndexOrWriteNode(short flags, Node receiver, ArgumentsNode arguments, Node block, Node value, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.receiver = receiver; this.arguments = arguments; this.block = block; - this.flags = flags; - this.operator = operator; this.value = value; } @@ -4475,6 +4963,14 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.receiver != null) { @@ -4494,7 +4990,7 @@ public Node[] childNodes() { } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitIndexOperatorWriteNode(this); + return visitor.visitIndexOrWriteNode(this); } @Override @@ -4507,6 +5003,10 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("receiver: "); builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); builder.append(nextIndent); @@ -4516,14 +5016,6 @@ protected String toString(String indent) { builder.append("block: "); builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); - builder.append(nextIndent); - builder.append("operator: "); - builder.append('"').append(this.operator).append('"'); - builder.append('\n'); - builder.append(nextIndent); builder.append("value: "); builder.append(this.value.toString(nextIndent)); return builder.toString(); @@ -4531,28 +5023,33 @@ protected String toString(String indent) { } /** - * Represents the use of the `||=` operator on a call to `[]`. + * Represents assigning to an index. * - * foo.bar[baz] ||= value - * ^^^^^^^^^^^^^^^^^^^^^^ + * foo[bar], = 1 + * ^^^^^^^^ + * + * begin + * rescue => foo[bar] + * ^^^^^^^^ + * end + * + * for foo[bar] in baz do end + * ^^^^^^^^ */ - public static final class IndexOrWriteNode extends Node { - /** optional (can be null) */ + public static final class IndexTargetNode extends Node { + public final short flags; public final Node receiver; - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; - /** optional (can be null) */ + @Nullable public final Node block; - public final short flags; - public final Node value; - public IndexOrWriteNode(Node receiver, ArgumentsNode arguments, Node block, short flags, Node value, int startOffset, int length) { + public IndexTargetNode(short flags, Node receiver, ArgumentsNode arguments, Node block, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.receiver = receiver; this.arguments = arguments; this.block = block; - this.flags = flags; - this.value = value; } public boolean isSafeNavigation() { @@ -4562,26 +5059,31 @@ public boolean isSafeNavigation() { public boolean isVariableCall() { return CallNodeFlags.isVariableCall(this.flags); } + + public boolean isAttributeWrite() { + return CallNodeFlags.isAttributeWrite(this.flags); + } + + public boolean isIgnoreVisibility() { + return CallNodeFlags.isIgnoreVisibility(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { - if (this.receiver != null) { - this.receiver.accept(visitor); - } + this.receiver.accept(visitor); if (this.arguments != null) { this.arguments.accept(visitor); } if (this.block != null) { this.block.accept(visitor); } - this.value.accept(visitor); } public Node[] childNodes() { - return new Node[] { this.receiver, this.arguments, this.block, this.value }; + return new Node[] { this.receiver, this.arguments, this.block }; } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitIndexOrWriteNode(this); + return visitor.visitIndexTargetNode(this); } @Override @@ -4594,21 +5096,18 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("receiver: "); - builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(this.receiver.toString(nextIndent)); builder.append(nextIndent); builder.append("arguments: "); builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); builder.append(nextIndent); builder.append("block: "); builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); - builder.append(nextIndent); - builder.append("value: "); - builder.append(this.value.toString(nextIndent)); return builder.toString(); } } @@ -4902,6 +5401,22 @@ protected String toString(String indent) { * ^ */ public static final class IntegerNode extends Node { + /** + *
+         * Represents flag indicating the base of the integer
+         *
+         *     10    base decimal, value 10
+         *     0d10  base decimal, value 10
+         *     0b10  base binary, value 2
+         *     0o10  base octal, value 8
+         *     010   base octal, value 8
+         *     0x10  base hexidecimal, value 16
+         *
+         * A 0 prefix indicates the number has a different base.
+         * The d, b, o, and x prefixes indicate the base. If one of those
+         * four letters is omitted, the base is assumed to be octal.
+         * 
+ */ public final short flags; public IntegerNode(short flags, int startOffset, int length) { @@ -4913,14 +5428,14 @@ public boolean isBinary() { return IntegerBaseFlags.isBinary(this.flags); } - public boolean isOctal() { - return IntegerBaseFlags.isOctal(this.flags); - } - public boolean isDecimal() { return IntegerBaseFlags.isDecimal(this.flags); } + public boolean isOctal() { + return IntegerBaseFlags.isOctal(this.flags); + } + public boolean isHexadecimal() { return IntegerBaseFlags.isHexadecimal(this.flags); } @@ -4962,13 +5477,13 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^ */ public static final class InterpolatedMatchLastLineNode extends Node { - public final Node[] parts; public final short flags; + public final Node[] parts; - public InterpolatedMatchLastLineNode(Node[] parts, short flags, int startOffset, int length) { + public InterpolatedMatchLastLineNode(short flags, Node[] parts, int startOffset, int length) { super(startOffset, length); - this.parts = parts; this.flags = flags; + this.parts = parts; } public boolean isIgnoreCase() { @@ -5002,6 +5517,18 @@ public boolean isWindows31j() { public boolean isUtf8() { return RegularExpressionFlags.isUtf8(this.flags); } + + public boolean isForcedUtf8Encoding() { + return RegularExpressionFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return RegularExpressionFlags.isForcedBinaryEncoding(this.flags); + } + + public boolean isForcedUsAsciiEncoding() { + return RegularExpressionFlags.isForcedUsAsciiEncoding(this.flags); + } @Override public void setNewLineFlag(Source source, boolean[] newlineMarked) { @@ -5036,15 +5563,15 @@ protected String toString(String indent) { String nextIndent = indent + " "; String nextNextIndent = nextIndent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("parts: "); builder.append('\n'); for (Node child : this.parts) { builder.append(nextNextIndent).append(child.toString(nextNextIndent)); } - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -5056,13 +5583,13 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^ */ public static final class InterpolatedRegularExpressionNode extends Node { - public final Node[] parts; public final short flags; + public final Node[] parts; - public InterpolatedRegularExpressionNode(Node[] parts, short flags, int startOffset, int length) { + public InterpolatedRegularExpressionNode(short flags, Node[] parts, int startOffset, int length) { super(startOffset, length); - this.parts = parts; this.flags = flags; + this.parts = parts; } public boolean isIgnoreCase() { @@ -5096,6 +5623,18 @@ public boolean isWindows31j() { public boolean isUtf8() { return RegularExpressionFlags.isUtf8(this.flags); } + + public boolean isForcedUtf8Encoding() { + return RegularExpressionFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return RegularExpressionFlags.isForcedBinaryEncoding(this.flags); + } + + public boolean isForcedUsAsciiEncoding() { + return RegularExpressionFlags.isForcedUsAsciiEncoding(this.flags); + } @Override public void setNewLineFlag(Source source, boolean[] newlineMarked) { @@ -5130,15 +5669,15 @@ protected String toString(String indent) { String nextIndent = indent + " "; String nextNextIndent = nextIndent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("parts: "); builder.append('\n'); for (Node child : this.parts) { builder.append(nextNextIndent).append(child.toString(nextNextIndent)); } - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -5318,13 +5857,19 @@ protected String toString(String indent) { * ^^^^ */ public static final class KeywordHashNode extends Node { + public final short flags; public final Node[] elements; - public KeywordHashNode(Node[] elements, int startOffset, int length) { + public KeywordHashNode(short flags, Node[] elements, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.elements = elements; } - + + public boolean isSymbolKeys() { + return KeywordHashNodeFlags.isSymbolKeys(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { for (Nodes.Node child : this.elements) { child.accept(visitor); @@ -5350,6 +5895,10 @@ protected String toString(String indent) { String nextIndent = indent + " "; String nextNextIndent = nextIndent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("elements: "); builder.append('\n'); for (Node child : this.elements) { @@ -5367,7 +5916,7 @@ protected String toString(String indent) { * end */ public static final class KeywordRestParameterNode extends Node { - /** optional (can be null) */ + @Nullable public final String name; public KeywordRestParameterNode(String name, int startOffset, int length) { @@ -5411,14 +5960,16 @@ protected String toString(String indent) { */ public static final class LambdaNode extends Node { public final String[] locals; - /** optional (can be null) */ + public final int locals_body_index; + @Nullable public final Node parameters; - /** optional (can be null) */ + @Nullable public final Node body; - public LambdaNode(String[] locals, Node parameters, Node body, int startOffset, int length) { + public LambdaNode(String[] locals, int locals_body_index, Node parameters, Node body, int startOffset, int length) { super(startOffset, length); this.locals = locals; + this.locals_body_index = locals_body_index; this.parameters = parameters; this.body = body; } @@ -5457,6 +6008,10 @@ protected String toString(String indent) { builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); } builder.append(nextIndent); + builder.append("locals_body_index: "); + builder.append(this.locals_body_index); + builder.append('\n'); + builder.append(nextIndent); builder.append("parameters: "); builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); builder.append(nextIndent); @@ -5795,13 +6350,13 @@ protected String toString(String indent) { * ^^^^^^ */ public static final class MatchLastLineNode extends Node { - public final byte[] unescaped; public final short flags; + public final byte[] unescaped; - public MatchLastLineNode(byte[] unescaped, short flags, int startOffset, int length) { + public MatchLastLineNode(short flags, byte[] unescaped, int startOffset, int length) { super(startOffset, length); - this.unescaped = unescaped; this.flags = flags; + this.unescaped = unescaped; } public boolean isIgnoreCase() { @@ -5835,6 +6390,18 @@ public boolean isWindows31j() { public boolean isUtf8() { return RegularExpressionFlags.isUtf8(this.flags); } + + public boolean isForcedUtf8Encoding() { + return RegularExpressionFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return RegularExpressionFlags.isForcedBinaryEncoding(this.flags); + } + + public boolean isForcedUsAsciiEncoding() { + return RegularExpressionFlags.isForcedUsAsciiEncoding(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -5857,13 +6424,13 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); - builder.append("unescaped: "); - builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); - builder.append('\n'); - builder.append(nextIndent); builder.append("flags: "); builder.append(this.flags); builder.append('\n'); + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); return builder.toString(); } } @@ -6065,7 +6632,7 @@ protected String toString(String indent) { public static final class ModuleNode extends Node { public final String[] locals; public final Node constant_path; - /** optional (can be null) */ + @Nullable public final Node body; public final String name; @@ -6130,7 +6697,7 @@ protected String toString(String indent) { */ public static final class MultiTargetNode extends Node { public final Node[] lefts; - /** optional (can be null) */ + @Nullable public final Node rest; public final Node[] rights; @@ -6202,7 +6769,7 @@ protected String toString(String indent) { */ public static final class MultiWriteNode extends Node { public final Node[] lefts; - /** optional (can be null) */ + @Nullable public final Node rest; public final Node[] rights; public final Node value; @@ -6280,7 +6847,7 @@ protected String toString(String indent) { * ^^^^^^ */ public static final class NextNode extends Node { - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; public NextNode(ArgumentsNode arguments, int startOffset, int length) { @@ -6632,13 +7199,13 @@ protected String toString(String indent) { public static final class ParametersNode extends Node { public final Node[] requireds; public final Node[] optionals; - /** optional (can be null) */ + @Nullable public final Node rest; public final Node[] posts; public final Node[] keywords; - /** optional (can be null) */ + @Nullable public final Node keyword_rest; - /** optional (can be null) */ + @Nullable public final BlockParameterNode block; public ParametersNode(Node[] requireds, Node[] optionals, Node rest, Node[] posts, Node[] keywords, Node keyword_rest, BlockParameterNode block, int startOffset, int length) { @@ -6746,7 +7313,7 @@ protected String toString(String indent) { * ^^^^^^^^^ */ public static final class ParenthesesNode extends Node { - /** optional (can be null) */ + @Nullable public final Node body; public ParenthesesNode(Node body, int startOffset, int length) { @@ -6882,7 +7449,7 @@ protected String toString(String indent) { * ^^^^^^^^^^^ */ public static final class PostExecutionNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public PostExecutionNode(StatementsNode statements, int startOffset, int length) { @@ -6927,7 +7494,7 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^ */ public static final class PreExecutionNode extends Node { - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public PreExecutionNode(StatementsNode statements, int startOffset, int length) { @@ -7023,17 +7590,17 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ public static final class RangeNode extends Node { - /** optional (can be null) */ + public final short flags; + @Nullable public final Node left; - /** optional (can be null) */ + @Nullable public final Node right; - public final short flags; - public RangeNode(Node left, Node right, short flags, int startOffset, int length) { + public RangeNode(short flags, Node left, Node right, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.left = left; this.right = right; - this.flags = flags; } public boolean isExcludeEnd() { @@ -7067,15 +7634,15 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("left: "); builder.append(this.left == null ? "null\n" : this.left.toString(nextIndent)); builder.append(nextIndent); builder.append("right: "); builder.append(this.right == null ? "null\n" : this.right.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -7165,13 +7732,13 @@ protected String toString(String indent) { * ^^^^^^ */ public static final class RegularExpressionNode extends Node { - public final byte[] unescaped; public final short flags; + public final byte[] unescaped; - public RegularExpressionNode(byte[] unescaped, short flags, int startOffset, int length) { + public RegularExpressionNode(short flags, byte[] unescaped, int startOffset, int length) { super(startOffset, length); - this.unescaped = unescaped; this.flags = flags; + this.unescaped = unescaped; } public boolean isIgnoreCase() { @@ -7205,6 +7772,18 @@ public boolean isWindows31j() { public boolean isUtf8() { return RegularExpressionFlags.isUtf8(this.flags); } + + public boolean isForcedUtf8Encoding() { + return RegularExpressionFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return RegularExpressionFlags.isForcedBinaryEncoding(this.flags); + } + + public boolean isForcedUsAsciiEncoding() { + return RegularExpressionFlags.isForcedUsAsciiEncoding(this.flags); + } public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -7227,13 +7806,13 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); - builder.append("unescaped: "); - builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); - builder.append('\n'); - builder.append(nextIndent); builder.append("flags: "); builder.append(this.flags); builder.append('\n'); + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); return builder.toString(); } } @@ -7391,11 +7970,11 @@ protected String toString(String indent) { */ public static final class RescueNode extends Node { public final Node[] exceptions; - /** optional (can be null) */ + @Nullable public final Node reference; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - /** optional (can be null) */ + @Nullable public final RescueNode consequent; public RescueNode(Node[] exceptions, Node reference, StatementsNode statements, RescueNode consequent, int startOffset, int length) { @@ -7471,7 +8050,7 @@ protected String toString(String indent) { * end */ public static final class RestParameterNode extends Node { - /** optional (can be null) */ + @Nullable public final String name; public RestParameterNode(String name, int startOffset, int length) { @@ -7550,7 +8129,7 @@ protected String toString(String indent) { * ^^^^^^^^ */ public static final class ReturnNode extends Node { - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; public ReturnNode(ArgumentsNode arguments, int startOffset, int length) { @@ -7633,7 +8212,7 @@ protected String toString(String indent) { public static final class SingletonClassNode extends Node { public final String[] locals; public final Node expression; - /** optional (can be null) */ + @Nullable public final Node body; public SingletonClassNode(String[] locals, Node expression, Node body, int startOffset, int length) { @@ -7805,7 +8384,7 @@ protected String toString(String indent) { * ^^ */ public static final class SplatNode extends Node { - /** optional (can be null) */ + @Nullable public final Node expression; public SplatNode(Node expression, int startOffset, int length) { @@ -7914,6 +8493,14 @@ public StringNode(short flags, byte[] unescaped, int startOffset, int length) { this.unescaped = unescaped; } + public boolean isForcedUtf8Encoding() { + return StringFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return StringFlags.isForcedBinaryEncoding(this.flags); + } + public boolean isFrozen() { return StringFlags.isFrozen(this.flags); } @@ -7960,9 +8547,9 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^ */ public static final class SuperNode extends Node { - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; - /** optional (can be null) */ + @Nullable public final Node block; public SuperNode(ArgumentsNode arguments, Node block, int startOffset, int length) { @@ -8017,13 +8604,27 @@ protected String toString(String indent) { * ^^^ */ public static final class SymbolNode extends Node { + public final short flags; public final byte[] unescaped; - public SymbolNode(byte[] unescaped, int startOffset, int length) { + public SymbolNode(short flags, byte[] unescaped, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.unescaped = unescaped; } - + + public boolean isForcedUtf8Encoding() { + return SymbolFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return SymbolFlags.isForcedBinaryEncoding(this.flags); + } + + public boolean isForcedUsAsciiEncoding() { + return SymbolFlags.isForcedUsAsciiEncoding(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -8045,6 +8646,10 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("unescaped: "); builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); builder.append('\n'); @@ -8147,9 +8752,9 @@ protected String toString(String indent) { */ public static final class UnlessNode extends Node { public final Node predicate; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - /** optional (can be null) */ + @Nullable public final ElseNode consequent; public UnlessNode(Node predicate, StatementsNode statements, ElseNode consequent, int startOffset, int length) { @@ -8214,16 +8819,16 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^^ */ public static final class UntilNode extends Node { + public final short flags; public final Node predicate; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - public final short flags; - public UntilNode(Node predicate, StatementsNode statements, short flags, int startOffset, int length) { + public UntilNode(short flags, Node predicate, StatementsNode statements, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.predicate = predicate; this.statements = statements; - this.flags = flags; } public boolean isBeginModifier() { @@ -8260,15 +8865,15 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("predicate: "); builder.append(this.predicate.toString(nextIndent)); builder.append(nextIndent); builder.append("statements: "); builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -8283,7 +8888,7 @@ protected String toString(String indent) { */ public static final class WhenNode extends Node { public final Node[] conditions; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; public WhenNode(Node[] conditions, StatementsNode statements, int startOffset, int length) { @@ -8345,16 +8950,16 @@ protected String toString(String indent) { * ^^^^^^^^^^^^^^^^^^^^ */ public static final class WhileNode extends Node { + public final short flags; public final Node predicate; - /** optional (can be null) */ + @Nullable public final StatementsNode statements; - public final short flags; - public WhileNode(Node predicate, StatementsNode statements, short flags, int startOffset, int length) { + public WhileNode(short flags, Node predicate, StatementsNode statements, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.predicate = predicate; this.statements = statements; - this.flags = flags; } public boolean isBeginModifier() { @@ -8391,15 +8996,15 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("predicate: "); builder.append(this.predicate.toString(nextIndent)); builder.append(nextIndent); builder.append("statements: "); builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); - builder.append(nextIndent); - builder.append("flags: "); - builder.append(this.flags); - builder.append('\n'); return builder.toString(); } } @@ -8411,13 +9016,23 @@ protected String toString(String indent) { * ^^^^^ */ public static final class XStringNode extends Node { + public final short flags; public final byte[] unescaped; - public XStringNode(byte[] unescaped, int startOffset, int length) { + public XStringNode(short flags, byte[] unescaped, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.unescaped = unescaped; } - + + public boolean isForcedUtf8Encoding() { + return EncodingFlags.isForcedUtf8Encoding(this.flags); + } + + public boolean isForcedBinaryEncoding() { + return EncodingFlags.isForcedBinaryEncoding(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -8439,6 +9054,10 @@ protected String toString(String indent) { builder.append('\n'); String nextIndent = indent + " "; builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); builder.append("unescaped: "); builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); builder.append('\n'); @@ -8453,7 +9072,7 @@ protected String toString(String indent) { * ^^^^^^^ */ public static final class YieldNode extends Node { - /** optional (can be null) */ + @Nullable public final ArgumentsNode arguments; public YieldNode(ArgumentsNode arguments, int startOffset, int length) {