org.jruby.truffle.parser.Translator Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.parser;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.SourceIndexLength;
import org.jruby.truffle.language.arguments.CheckArityNode;
import org.jruby.truffle.language.arguments.CheckKeywordArityNode;
import org.jruby.truffle.language.arguments.ProfileArgumentNode;
import org.jruby.truffle.language.arguments.ReadSelfNode;
import org.jruby.truffle.language.control.SequenceNode;
import org.jruby.truffle.language.literal.NilLiteralNode;
import org.jruby.truffle.language.locals.WriteLocalVariableNode;
import org.jruby.truffle.language.methods.Arity;
import org.jruby.truffle.language.objects.SelfNode;
import org.jruby.truffle.parser.ast.NilImplicitParseNode;
import org.jruby.truffle.parser.ast.ParseNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class Translator extends org.jruby.truffle.parser.ast.visitor.AbstractNodeVisitor {
public static final Set FRAME_LOCAL_GLOBAL_VARIABLES = new HashSet<>(
Arrays.asList("$_", "$~", "$+", "$&", "$`", "$'", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9"));
static final Set READ_ONLY_GLOBAL_VARIABLES = new HashSet<>(
Arrays.asList("$:", "$LOAD_PATH", "$-I", "$\"", "$LOADED_FEATURES", "$<", "$FILENAME", "$?", "$-a", "$-l", "$-p", "$!"));
static final Set ALWAYS_DEFINED_GLOBALS = new HashSet<>(Arrays.asList("$!", "$~"));
static final Set THREAD_LOCAL_GLOBAL_VARIABLES = new HashSet<>(Arrays.asList("$!", "$?")); // "$_"
static final Map GLOBAL_VARIABLE_ALIASES = new HashMap<>();
static {
Map m = GLOBAL_VARIABLE_ALIASES;
m.put("$-I", "$LOAD_PATH");
m.put("$:", "$LOAD_PATH");
m.put("$-d", "$DEBUG");
m.put("$-v", "$VERBOSE");
m.put("$-w", "$VERBOSE");
m.put("$-0", "$/");
m.put("$RS", "$/");
m.put("$INPUT_RECORD_SEPARATOR", "$/");
m.put("$>", "$stdout");
m.put("$PROGRAM_NAME", "$0");
}
protected final Node currentNode;
protected final RubyContext context;
protected final Source source;
public Translator(Node currentNode, RubyContext context, Source source) {
this.currentNode = currentNode;
this.context = context;
this.source = source;
}
public static RubyNode sequence(SourceIndexLength sourceSection, List sequence) {
final List flattened = flatten(sequence, true);
if (flattened.isEmpty()) {
final RubyNode literal = new NilLiteralNode(true);
literal.unsafeSetSourceSection(sourceSection);
return literal;
} else if (flattened.size() == 1) {
return flattened.get(0);
} else {
final RubyNode[] flatSequence = flattened.toArray(new RubyNode[flattened.size()]);
final SourceIndexLength enclosingSourceSection = enclosing(sourceSection, flatSequence);
return withSourceSection(enclosingSourceSection, new SequenceNode(flatSequence));
}
}
public static SourceIndexLength enclosing(SourceIndexLength base, RubyNode... sequence) {
if (base == null) {
return base;
}
int start = base.getCharIndex();
int end = base.getCharEnd();
for (RubyNode node : sequence) {
final SourceIndexLength sourceSection = node.getSourceIndexLength();
if (sourceSection != null) {
start = Integer.min(start, sourceSection.getCharIndex());
end = Integer.max(end, sourceSection.getCharEnd());
}
}
return new SourceIndexLength(start, end - start);
}
private static List flatten(List sequence, boolean allowTrailingNil) {
final List flattened = new ArrayList<>();
for (int n = 0; n < sequence.size(); n++) {
final boolean lastNode = n == sequence.size() - 1;
final RubyNode node = sequence.get(n);
if (node instanceof NilLiteralNode && ((NilLiteralNode) node).isImplicit()) {
if (allowTrailingNil && lastNode) {
flattened.add(node);
}
} else if (node instanceof SequenceNode) {
flattened.addAll(flatten(Arrays.asList(((SequenceNode) node).getSequence()), lastNode));
} else {
flattened.add(node);
}
}
return flattened;
}
protected RubyNode nilNode(Source source, SourceIndexLength sourceSection) {
final RubyNode literal = new NilLiteralNode(false);
literal.unsafeSetSourceSection(sourceSection);
return literal;
}
protected RubyNode translateNodeOrNil(SourceIndexLength sourceSection, ParseNode node) {
final RubyNode rubyNode;
if (node == null || node instanceof NilImplicitParseNode) {
rubyNode = nilNode(source, sourceSection);
} else {
rubyNode = node.accept(this);
}
return rubyNode;
}
public static RubyNode createCheckArityNode(Arity arity) {
if (!arity.acceptsKeywords()) {
return new CheckArityNode(arity);
} else {
return new CheckKeywordArityNode(arity);
}
}
public SourceSection translateSourceSection(Source source, SourceIndexLength sourceSection) {
if (sourceSection == null) {
return null;
} else {
return sourceSection.toSourceSection(source);
}
}
public static RubyNode loadSelf(RubyContext context, TranslatorEnvironment environment) {
final FrameSlot slot = environment.getFrameDescriptor().findOrAddFrameSlot(SelfNode.SELF_IDENTIFIER);
SourceIndexLength sourceSection = null;
return WriteLocalVariableNode.createWriteLocalVariableNode(context, slot, new ProfileArgumentNode(new ReadSelfNode()));
}
public static T withSourceSection(SourceIndexLength sourceSection, T node) {
if (sourceSection != null) {
node.unsafeSetSourceSection(sourceSection);
}
return node;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy