blob: edabd1d695da78f8e02f778b3a31827b889fe7cc [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rtm.base.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.rtm.rtdata.types.RTypedExpr;
public abstract class AbstractRCodeGenerator {
protected static final RTypedExpr R_NUM_ZERO_EXPR= new RTypedExpr(RTypedExpr.R, "0"); //$NON-NLS-1$
protected static String quoteChar(final String s) {
final StringBuilder result= new StringBuilder(s.length());
result.append('"');
for (int i= 0; i < s.length(); ) {
final char c= s.charAt(i++);
switch (c) {
case '\\':
case '\'':
case '"':
result.append('\\');
result.append(c);
continue;
default:
result.append(c);
continue;
}
}
result.append('"');
return result.toString();
}
protected static interface IRExprProcessor {
String getValue(RTypedExpr expr);
}
protected static final IRExprProcessor DIRECT_PROCESSOR= new IRExprProcessor() {
@Override
public String getValue(final RTypedExpr expr) {
return expr.getExpr();
}
};
protected static final IRExprProcessor TEXT_PROCESSOR= new IRExprProcessor() {
@Override
public String getValue(final RTypedExpr expr) {
return quoteChar(expr.getExpr());
}
};
protected static final IRExprProcessor QUOTE_PROCESSOR= new IRExprProcessor() {
@Override
public String getValue(final RTypedExpr expr) {
return quoteChar(expr.getExpr());
}
};
protected class FunBuilder {
private final int offset;
private final int emtpyOffset;
public FunBuilder(final int offset, final String funName) {
this.offset= offset;
AbstractRCodeGenerator.this.builder.append(funName);
AbstractRCodeGenerator.this.builder.append('(');
this.emtpyOffset= AbstractRCodeGenerator.this.builder.length();
}
public boolean isEmpty() {
return (AbstractRCodeGenerator.this.builder.length() == this.emtpyOffset);
}
public boolean append(final String argName, final String argValue) {
if (argValue == null) {
return false;
}
doAppendArg(argName, argValue);
return true;
}
public boolean append(final String argName, final String argValue, final boolean appendEmpty) {
if (argValue == null && !appendEmpty) {
return false;
}
doAppendArg(argName, argValue);
return true;
}
public boolean appendEmpty(final String argName) {
doAppendArg(argName, null);
return true;
}
public boolean appendExpr(final String argName, final RTypedExpr argValue) {
if (argValue == null) {
return false;
}
doAppendArg(argName, getRExprPRocessor(argValue.getTypeKey()).getValue(argValue));
return true;
}
public boolean appendExpr(final String argName, final RTypedExpr argValue,
final String requiredType) {
if (argValue == null || argValue.getTypeKey() != requiredType) {
return false;
}
doAppendArg(argName, getRExprPRocessor(argValue.getTypeKey()).getValue(argValue));
return true;
}
public boolean appendExpr(final String argName, final RTypedExpr argValue,
final Collection<String> requiredTypes) {
if (argValue == null || !requiredTypes.contains(argValue.getTypeKey())) {
return false;
}
doAppendArg(argName, getRExprPRocessor(argValue.getTypeKey()).getValue(argValue));
return true;
}
public FunBuilder appendFun(final String argName, final String funName) {
final int offset= AbstractRCodeGenerator.this.builder.length();
doAppendArg(argName, null);
return new FunBuilder(offset, funName);
}
private void doAppendArg(final String argName, final String argValue) {
if (!isEmpty()) {
AbstractRCodeGenerator.this.builder.append(", "); //$NON-NLS-1$
}
if (argName != null) {
AbstractRCodeGenerator.this.builder.append(argName);
AbstractRCodeGenerator.this.builder.append(AbstractRCodeGenerator.this.argAssign);
}
if (argValue != null) {
AbstractRCodeGenerator.this.builder.append(argValue);
}
}
public void close() {
AbstractRCodeGenerator.this.builder.append(")"); //$NON-NLS-1$
}
public void closeOrRemove() {
if (isEmpty()) {
AbstractRCodeGenerator.this.builder.delete(this.offset, AbstractRCodeGenerator.this.builder.length());
return;
}
AbstractRCodeGenerator.this.builder.append(")"); //$NON-NLS-1$
}
}
protected final List<String> requiredPkgs= new ArrayList<>();
protected final StringBuilder builder= new StringBuilder();
private final String newLine= "\n";
private final String mainAssign= " <- ";
private final String argAssign= " = ";
private final int indent= 0;
public AbstractRCodeGenerator() {
}
protected void reset() {
this.requiredPkgs.clear();
this.builder.setLength(0);
}
protected void addRequirePackage(final String pkgName) {
if (!this.requiredPkgs.contains(pkgName)) {
this.requiredPkgs.add(pkgName);
final FunBuilder fun= appendFun("library"); //$NON-NLS-1$
fun.append(null, pkgName);
fun.close();
appendNewLine();
}
}
protected void appendNewLine() {
this.builder.append(this.newLine);
}
protected void appendAssign(final String to) {
this.builder.append(to);
this.builder.append(this.mainAssign);
}
protected FunBuilder appendFun(final String funName) {
return new FunBuilder(this.builder.length(), funName);
}
protected void appendExprList(final List<? extends RTypedExpr> list,
final String op, final String empty) {
appendExprList(list, DIRECT_PROCESSOR, op, empty);
}
protected void appendExprList(final List<? extends RTypedExpr> list,
final IRExprProcessor processor, final String op, final String empty) {
final int offset= this.builder.length();
for (int i= 0; i < list.size(); i++) {
final RTypedExpr expr= list.get(i);
if (expr.getTypeKey() == RTypedExpr.MAPPED) {
if (this.builder.length() > offset) {
this.builder.append(op);
}
this.builder.append(processor.getValue(list.get(i)));
}
}
if (this.builder.length() == offset && empty != null) {
this.builder.append(empty);
}
}
protected void appendExprsC(final List<? extends RTypedExpr> list,
final IRExprProcessor processor) {
this.builder.append("c("); //$NON-NLS-1$
appendExprList(list, processor, ", ", null); //$NON-NLS-1$
this.builder.append(")"); //$NON-NLS-1$
}
protected IRExprProcessor getRExprPRocessor(final String typeKey) {
if (typeKey == RTypedExpr.CHAR) {
return TEXT_PROCESSOR;
}
return DIRECT_PROCESSOR;
}
public abstract void generate(EObject root);
public List<String> getRequiredPkgs() {
return ImCollections.toList(this.requiredPkgs);
}
public String getRCode() {
return this.builder.toString();
}
}