/* * Copyright 2019, Perfect Sense, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gyro.lang.ast.value; import java.util.Map; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import gyro.lang.EscapeException; import gyro.lang.ast.Node; import gyro.lang.ast.NodeVisitor; import gyro.parser.antlr4.GyroParser; import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; public class ValueNode extends Node { private final Object value; // Escape character private static final Map<Character, Character> ESCAPE = new ImmutableMap.Builder<Character, Character>() .put('t', '\t') .put('n', '\n') .put('r', '\r') .put('"', '"') .put('\'', '\'') .put('\\', '\\').build(); public ValueNode(Object value) { super(null); this.value = Preconditions.checkNotNull(value); } public ValueNode(GyroParser.BoolContext context) { super(Preconditions.checkNotNull(context)); this.value = context.TRUE() != null; } public ValueNode(GyroParser.LiteralStringContext context) { super(Preconditions.checkNotNull(context)); this.value = getContextText(context.stringLiteral()); } public ValueNode(GyroParser.NumberContext context) { super(Preconditions.checkNotNull(context)); String text = context.getText(); if (text.contains(".")) { this.value = Double.valueOf(text); } else { this.value = Long.valueOf(text); } } public ValueNode(GyroParser.TextContext context) { super(Preconditions.checkNotNull(context)); this.value = getContextText(context); } public ValueNode(GyroParser.TypeContext context) { super(Preconditions.checkNotNull(context)); this.value = context.getText(); } public ValueNode(GyroParser.WordContext context) { super(Preconditions.checkNotNull(context)); this.value = context.getText(); } public ValueNode(TerminalNode context) { super(context.getSymbol(), context.getSymbol()); this.value = context.getText(); } public Object getValue() { return value; } private String getContextText(RuleContext context) { if (context.getChildCount() == 0) { return ""; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < context.getChildCount(); i++) { ParseTree child = context.getChild(i); if (child instanceof GyroParser.EscapeContext) { builder.append(getEscapeText((GyroParser.EscapeContext) child)); } else { builder.append(child.getText()); } } return builder.toString(); } private String getEscapeText(GyroParser.EscapeContext context) { return ESCAPE.entrySet() .stream() .filter(e -> e.getKey().equals(context.getText().charAt(1))) .findFirst() .map(Map.Entry::getValue) .map(String::valueOf) .orElseThrow(() -> new EscapeException(context.getText(), context.ESCAPE().getSymbol())); } @Override public <C, R, X extends Throwable> R accept(NodeVisitor<C, R, X> visitor, C context) throws X { return visitor.visitValue(this, context); } }