Skip to content

Commit

Permalink
#45: added fundamental record support
Browse files Browse the repository at this point in the history
  • Loading branch information
hohwille committed Feb 11, 2023
1 parent 60fd8ed commit 3cf878a
Show file tree
Hide file tree
Showing 18 changed files with 649 additions and 204 deletions.
12 changes: 11 additions & 1 deletion api/src/main/java/io/github/mmm/code/api/item/CodeItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ public abstract interface CodeItem {
/** The default indent (2 spaces). */
String DEFAULT_INDENT = " ";

/**
* @return the source-code of this item.
*/
default String write() {

StringBuilder sb = new StringBuilder();
write(sb);
return sb.toString();
}

/**
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the
* {@link #getSourceCode() source code} from this {@link CodeItem}.
Expand Down Expand Up @@ -52,8 +62,8 @@ default void write(Appendable sink, String newline, String defaultIndent) {
/**
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the
* {@link #getSourceCode() source code} from this {@link CodeItem}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
*/
Expand Down

Large diffs are not rendered by default.

97 changes: 75 additions & 22 deletions api/src/main/java/io/github/mmm/code/api/language/CodeLanguage.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import io.github.mmm.code.api.expression.CodeVariable;
import io.github.mmm.code.api.item.CodeItemWithName;
import io.github.mmm.code.api.item.CodeItemWithQualifiedName;
import io.github.mmm.code.api.member.CodeConstructor;
import io.github.mmm.code.api.member.CodeField;
import io.github.mmm.code.api.member.CodeMethod;
import io.github.mmm.code.api.statement.CodeLocalVariable;
import io.github.mmm.code.api.type.CodeType;
import io.github.mmm.code.api.type.CodeTypeCategory;
Expand Down Expand Up @@ -50,25 +53,74 @@ public interface CodeLanguage {
void writeDeclaration(CodeVariable variable, Appendable sink) throws IOException;

/**
* @return the {@link String} to add prefixed by the {@link io.github.mmm.code.api.arg.CodeReturn} before the
* {@link io.github.mmm.code.api.member.CodeMethod#getName() method name} or {@code null} if the
* {@link io.github.mmm.code.api.arg.CodeReturn} shall be written with {@link #getMethodReturnEnd()}.
* Writes a type declaration (e.g. "public class MyClass").
*
* @param type the {@link CodeType} to write.
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the code to.
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
* @throws IOException if thrown by {@link Appendable}.
*/
default String getMethodReturnStart() {
void writeDeclaration(CodeType type, Appendable sink, String newline, String defaultIndent, String currentIndent)
throws IOException;

return "";
}
/**
* Writes the type body (e.g. "{\n private String field;\n }\n").
*
* @param type the {@link CodeType} to write.
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the code to.
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
* @throws IOException if thrown by {@link Appendable}.
*/
void writeBody(CodeType type, Appendable sink, String newline, String defaultIndent, String currentIndent)
throws IOException;

/**
* Writes the given field (e.g. "private String field;\n").
*
* @param field the {@link CodeField} to write.
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the code to.
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
* @throws IOException if thrown by {@link Appendable}.
*/
void writeField(CodeField field, Appendable sink, String newline, String defaultIndent, String currentIndent)
throws IOException;

/**
* @return the {@link String} to add followed by the {@link io.github.mmm.code.api.arg.CodeReturn} after the
* {@link io.github.mmm.code.api.member.CodeMethod#getParameters() method parameters} or {@code null} if the
* {@link io.github.mmm.code.api.arg.CodeReturn} shall be written with {@link #getMethodReturnStart()}. E.g. ": "
* for TypeScript or Kotlin.
* Writes the given method (e.g. "String getName();\n").
*
* @param method the {@link CodeField} to write.
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the code to.
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
* @throws IOException if thrown by {@link Appendable}.
*/
default String getMethodReturnEnd() {
void writeMethod(CodeMethod method, Appendable sink, String newline, String defaultIndent, String currentIndent)
throws IOException;

return null;
}
/**
* Writes the given {@link CodeConstructor}.
*
* @param constructor the {@link CodeConstructor} to write.
* @param sink the {@link Appendable} where to {@link Appendable#append(CharSequence) append} the code to.
* @param newline the newline {@link String}.
* @param defaultIndent the {@link String} used for indentation (e.g. a number of spaces to insert per indent level).
* @param currentIndent the current indent (number of spaces). Initially the empty string ({@code ""}). Before a
* recursion the {@code defaultIndent} will be appended.
* @throws IOException if thrown by {@link Appendable}.
*/
void writeConstructor(CodeConstructor constructor, Appendable sink, String newline, String defaultIndent,
String currentIndent) throws IOException;

/**
* @return the " extends " keyword (May also be " : " for Kotlin).
Expand Down Expand Up @@ -101,8 +153,8 @@ default String getMethodKeyword() {
}

/**
* @return the {@link String} used as suffix to terminate a {@link io.github.mmm.code.api.statement.CodeAtomicStatement}.
* E.g. ";".
* @return the {@link String} used as suffix to terminate a
* {@link io.github.mmm.code.api.statement.CodeAtomicStatement}. E.g. ";".
*/
String getStatementTerminator();

Expand All @@ -116,9 +168,9 @@ default String getAnnotationStart() {

/**
* @return the {@link String} to signal the end of an empty {@link io.github.mmm.code.api.annotation.CodeAnnotation}.
* Here empty means that the {@link io.github.mmm.code.api.annotation.CodeAnnotation#getParameters() parameters}
* are {@link java.util.Map#isEmpty() empty}. E.g. for TypeScript even an empty annotation has to be
* terminated with "()".
* Here empty means that the {@link io.github.mmm.code.api.annotation.CodeAnnotation#getParameters()
* parameters} are {@link java.util.Map#isEmpty() empty}. E.g. for TypeScript even an empty annotation has to
* be terminated with "()".
*/
default String getAnnotationEndIfEmpty() {

Expand Down Expand Up @@ -162,14 +214,15 @@ default char getPackageSeparator() {
String getFileFilename(CodeFile file);

/**
* @return {@code true} if this language natively supports {@link io.github.mmm.code.api.member.CodeProperty properties}
* (in such case
* @return {@code true} if this language natively supports {@link io.github.mmm.code.api.member.CodeProperty
* properties} (in such case
* {@link io.github.mmm.code.api.CodeFactory#createField(io.github.mmm.code.api.member.CodeFields, String, java.lang.reflect.Field)}
* needs to provide an implementation that also implements {@link io.github.mmm.code.api.member.CodeProperty}),
* {@code false} otherwise.
* needs to provide an implementation that also implements
* {@link io.github.mmm.code.api.member.CodeProperty}), {@code false} otherwise.
*/
default boolean isSupportingNativeProperties() {

return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
* http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.code.api.language;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

import io.github.mmm.code.api.CodeFile;
import io.github.mmm.code.api.CodePackage;
import io.github.mmm.code.api.expression.CodeVariable;
import io.github.mmm.code.api.expression.CodeVariableThis;
import io.github.mmm.code.api.item.CodeItem;
import io.github.mmm.code.api.item.CodeItemWithName;
Expand Down Expand Up @@ -41,10 +39,11 @@ public class JavaLanguage extends AbstractCodeLanguage {
static final Pattern NAME_PATTERN_TYPE = NAME_PATTERN;

private static final Set<String> REVERVED_NAMES = new HashSet<>(
Arrays.asList("abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do",
"if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws",
"case", "enum", "instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final", "interface",
"static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", "while"));
Arrays.asList("abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package",
"synchronized", "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected",
"throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
"long", "strictfp", "volatile", "const", "float", "native", "super", "while"));

/** The singleton instance. */
private static final JavaLanguage INSTANCE = new JavaLanguage();
Expand Down Expand Up @@ -74,14 +73,6 @@ public String getKeywordForVariable(CodeLocalVariable variable) {
return keyword;
}

@Override
public void writeDeclaration(CodeVariable variable, Appendable sink) throws IOException {

variable.writeReference(sink, false);
sink.append(' ');
sink.append(variable.getName());
}

@Override
public String getKeywordForCategory(CodeTypeCategory category) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public final class CodeTypeCategory {
/** {@link CodeTypeCategory} for an {@link Class#isAnnotation() annotation}. */
public static final CodeTypeCategory ANNOTATION = new CodeTypeCategory("annotation");

/** {@link CodeTypeCategory} for an {@link Class#isRecord() annotation}. */
public static final CodeTypeCategory RECORD = new CodeTypeCategory("record");

private final String value;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ public void testBasics() {
assertThat(language.getAnnotationEndIfEmpty()).isEmpty();
assertThat(language.getVariableNameThis()).isEqualTo("this");
assertThat(language.getMethodKeyword()).isEmpty();
assertThat(language.getMethodReturnStart()).isEmpty();
assertThat(language.getMethodReturnEnd()).isNull();
assertThat(language.getKeywordForCategory(CodeTypeCategory.CLASS)).isEqualTo("class");
assertThat(language.getKeywordForCategory(CodeTypeCategory.INTERFACE)).isEqualTo("interface");
assertThat(language.getKeywordForCategory(CodeTypeCategory.ENUMERAION)).isEqualTo("enum");
assertThat(language.getKeywordForCategory(CodeTypeCategory.ANNOTATION)).isEqualTo("@interface");
assertThat(language.getKeywordForCategory(CodeTypeCategory.RECORD)).isEqualTo("record");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
* http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.code.base.element;

import java.io.IOException;
import java.util.Objects;

import io.github.mmm.code.api.copy.CodeCopyMapper;
import io.github.mmm.code.api.element.CodeElementWithModifiers;
import io.github.mmm.code.api.language.CodeLanguage;
import io.github.mmm.code.api.modifier.CodeModifiers;

/**
Expand All @@ -16,7 +14,8 @@
* @author Joerg Hohwiller (hohwille at users.sourceforge.net)
* @since 1.0.0
*/
public abstract class BaseElementWithModifiers extends BaseElementWithDeclaringType implements CodeElementWithModifiers {
public abstract class BaseElementWithModifiers extends BaseElementWithDeclaringType
implements CodeElementWithModifiers {

private CodeModifiers modifiers;

Expand Down Expand Up @@ -60,21 +59,4 @@ public void setModifiers(CodeModifiers modifiers) {
@Override
public abstract BaseElementWithModifiers copy();

@Override
protected void doWrite(Appendable sink, String newline, String defaultIndent, String currentIndent, CodeLanguage language) throws IOException {

super.doWrite(sink, newline, defaultIndent, currentIndent, language);
sink.append(currentIndent);
doWriteModifiers(sink);
}

/**
* @param sink the {@link Appendable}.
* @throws IOException if thrown by {@link Appendable}.
*/
protected void doWriteModifiers(Appendable sink) throws IOException {

sink.append(this.modifiers.toString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
* http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.code.base.member;

import java.io.IOException;
import java.lang.reflect.Constructor;

import io.github.mmm.base.exception.ReadOnlyException;
import io.github.mmm.code.api.copy.CodeCopyMapper;
import io.github.mmm.code.api.copy.CodeCopyType;
import io.github.mmm.code.api.language.CodeLanguage;
import io.github.mmm.code.api.member.CodeConstructor;
import io.github.mmm.code.api.member.CodeConstructors;
import io.github.mmm.code.api.merge.CodeMergeStrategy;
Expand Down Expand Up @@ -139,4 +141,11 @@ public BaseConstructor copy(CodeCopyMapper mapper) {
return new BaseConstructor(this, mapper);
}

@Override
protected void doWrite(Appendable sink, String newline, String defaultIndent, String currentIndent,
CodeLanguage language) throws IOException {

language.writeConstructor(this, sink, newline, defaultIndent, currentIndent);
}

}
21 changes: 8 additions & 13 deletions base/src/main/java/io/github/mmm/code/base/member/BaseField.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ public CodeMethod getOrCreateGetter() {

getGetter();
if (this.getter == null) {
this.getter = getContext().getFactory().createGetter(getDeclaringType(), getName(), getType(), true, getDoc().getLinesAsArray());
this.getter = getContext().getFactory().createGetter(getDeclaringType(), getName(), getType(), true,
getDoc().getLinesAsArray());
this.parent.getParent().getMethods().add(this.getter);
}
return this.getter;
Expand All @@ -240,24 +241,18 @@ public CodeMethod getOrCreateSetter() {

getSetter();
if (this.setter == null) {
this.setter = getContext().getFactory().createSetter(getDeclaringType(), getName(), getType(), true, getDoc().getLinesAsArray());
this.setter = getContext().getFactory().createSetter(getDeclaringType(), getName(), getType(), true,
getDoc().getLinesAsArray());
this.parent.getParent().getMethods().add(this.setter);
}
return this.setter;
}

@Override
protected void doWrite(Appendable sink, String newline, String defaultIndent, String currentIndent, CodeLanguage language)
throws IOException {

super.doWrite(sink, newline, defaultIndent, currentIndent, language);
language.writeDeclaration(this, sink);
if (this.initializer != null) {
sink.append(" = ");
this.initializer.write(sink, "", "");
}
sink.append(';');
sink.append(newline);
protected void doWrite(Appendable sink, String newline, String defaultIndent, String currentIndent,
CodeLanguage language) throws IOException {

language.writeField(this, sink, newline, defaultIndent, currentIndent);
}

}
Loading

0 comments on commit 3cf878a

Please sign in to comment.