Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sin builtin #2

Merged
merged 11 commits into from
Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.idea/libraries/
.idea/misc.xml
.idea/uiDesigner.xml
/preprolanguage/native/prepronative
/preprolanguage/component/prepro-component.jar
98 changes: 98 additions & 0 deletions Documentation/HowTos/Builtin Erstellen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Builtin Erstellen

Vorbedingung: Das Projekt muss bereits ausgecheckt und lauffähig sein.

## Was ist ein Builtin
Unter builtins werden alle Funktionen zusammengefasst, die PrePro bereits von Haus aus mitliefert (die in die Sprache "eingebaut" sind).
Das bedeutet, sie können direkt in jedem Skript aufgerufen werden.


## Welche Builtins gibt es

Es gibt zwei Sorten von Builtins: Interne und externe.

Interne Builtins sind immer verfügbar. Externe können von der jeweiligen Laufzeitumgebung hinzugefügt werden.
Zum Zeitpunkt des Erstellens dieses Dokuments gibt es nur interne Builtins.

Da die Liste der existierenden Builtins schnell veralten würde, hier wie man die registrierten Builtins findet:
In `PreProContext#installBuiltins` werden die Builtins registriert.
Daher können alle Builtins dort direkt eingesehen werden.


## Neue Builtins anlegen

Im Nachfolgenden wird das Builtin für die Sinusfunktion `sin(x)` angelegt.

### Builtin Klasse Erzeugen

Um ein neues Builtin anzulegen, muss eine abstrakte Klasse erstellt werden, die `PreProBuiltinNode` erweitert.
Gleichzeitig wird der Name des Builtins (und damit auch der Funktionsname, unter dem es aufgerufen wird) mittels der `@NodeInfo` Annotation übergeben.
```java
@NodeInfo(shortName = "sin")
public abstract class PreProSinBuiltin extends PreProBuiltinNode {
}
```

### Projekt kompilieren

Das Erweitern der PreProBuiltinNode sorgt dafür, dass beim nächsten Kompilieren der Annotationsprozessor von Truffle eine neue Klasse erzeugt. Diese hat den Namen der Builtin Klasse plus die Endung `Factory`.
Falls die die Klasse nicht gefunden wird, die IDE darauf anweisen, den `target/generated-sources/annotations` Ordner neu zu indizieren. Je nach build Einstellung kann es möglich sein, dass über Maven `mvn compile` gebaut werden muss.

```java
@GeneratedBy(PreProPrintBuiltin.class)
public final class PreProPrintBuiltinFactory implements NodeFactory<PreProPrintBuiltin> {
//Generierter Code
}
```

### BuiltinFactory registrieren

Eine Instanz der Factory-Klasse muss nun im `PreProContext` registriert werden.
Das Registrieren sorgt dafür, dass das Builtin benutzt werden kann.

Die Factory-Klassen sind nach dem Singleton Pattern aufgebaut und besitzen daher eine `getInstance()` Methode.
Registriert werden die Instanzen innerhalb von `PreProContext#installBuiltins`.

```java
private void installBuiltins() {
//... Bereits existierende Builtins ...//

installBuiltin(PreProSinBuiltinFactory.getInstance());
}
```

### Spezialisierungen erstellen

Das bisher erzeugte Builtin kann zwar benutzt werden, besitzt allerdings noch keine wirkliche Funktionalität.
Nun muss die Builtin Klasse dahingehend erweitert werden, dass die entsprechenden Methodensignaturen unterstützt werden.

Hierfür werden Instanzmethoden innerhalb des Builtins geschrieben, und mit der Annotation `@Specialization` versehen.
Die Annotation sorgt dafür. Dass die vom Annotationsprozessor erzeugte Klasse die für die Argumente passende Implementierung wählt.

Nur mit `@Specialization` versehene Methoden werden berücksichtigt!.
Des Weiteren ist zu beachten, dass die Reihenfolge der Methoden für den Annotationsprozessor eine Rolle spielt. PrePro wird die verschiedenen Signaturen von oben nach unten "durchprobieren". Daher müssen spezifischere Methodensignaturen weiter oben stehen als weniger spezifische. Der Annotationsprozessor gibt bei Missachten lediglich Warnungen auf der Konsole aus, die leicht überlesen werden können.

Eine Beispielhafte Methode sieht so aus.

```java
@Specialization
public PreProConstant sin(PreProConstant constant) {
return new PreProConstant(Transforms.sin(constant.timeSeries(), true));
}
```


#### Arbeiten mit Elementweisen Transformierungen

Für viele Builtins muss eine Operation auf jedes Element der Matrix angewendet werden.
Für die Standard-Funktionen bietet ND4J hierfür bereits Operatoren an. Diese sind in der Klasse `org.nd4j.linalg.ops.transforms.Transforms` zu finden.


### Packagen und Ausführen

Die bisherigen Änderungen sind zwar bisher im Code, aber noch nicht im Jar. Dafür ein `mvn clean package` ausführen, um alles zu packagen, dann kann man auch damit testen.


### Tests

Und am Ende natürlich noch Tests schreiben :smile:
8 changes: 8 additions & 0 deletions preprolanguage/PI_Incrementer.prepro
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ function main() {
print("");
print("0 if variable does not exist:");
print(exists anotherVariable);

print("");
print("sin(3) = ");
print(sin(3));

print("");
print("cos(3) = ");
print(cos(3));
}

function increment(const varConst) returns const {
Expand Down
2 changes: 1 addition & 1 deletion preprolanguage/component/clean_component.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash

[[ -f sl-component.jar ]] && rm sl-component.jar || echo "sl-component.jar not found"
[[ -f prepro-component.jar ]] && rm prepro-component.jar || echo "prepro-component.jar not found"
6 changes: 3 additions & 3 deletions preprolanguage/component/make_component.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ else
exit 1
fi
readonly COMPONENT_DIR="component_temp_dir"
readonly LANGUAGE_PATH="$COMPONENT_DIR/$JRE/languages/sl"
readonly LANGUAGE_PATH="$COMPONENT_DIR/$JRE/languages/prepro"
if [[ -f ../native/prepronative ]]; then
INCLUDE_PREPRONATIVE="TRUE"
fi
Expand All @@ -24,7 +24,7 @@ mkdir -p "$LANGUAGE_PATH/launcher"
cp ../launcher/target/prepro-launcher.jar "$LANGUAGE_PATH/launcher/"

mkdir -p "$LANGUAGE_PATH/bin"
cp ../sl $LANGUAGE_PATH/bin/
cp ../prepro $LANGUAGE_PATH/bin/
if [[ $INCLUDE_PREPRONATIVE = "TRUE" ]]; then
cp ../native/prepronative $LANGUAGE_PATH/bin/
fi
Expand All @@ -34,7 +34,7 @@ touch "$LANGUAGE_PATH/native-image.properties"
mkdir -p "$COMPONENT_DIR/META-INF"
{
echo "Bundle-Name: PrePro";
echo "Bundle-Symbolic-Name: com.oracle.truffle.sl";
echo "Bundle-Symbolic-Name: com.oracle.truffle.prepro";
echo "Bundle-Version: 20.2.0";
echo 'Bundle-RequireCapability: org.graalvm; filter:="(&(graalvm_version=20.2.0)(os_arch=amd64))"';
echo "x-GraalVM-Polyglot-Part: True"
Expand Down
Binary file removed preprolanguage/component/prepro-component.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.oracle.truffle.prepro.builtins;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.prepro.runtime.types.*;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.ops.transforms.Transforms;

@NodeInfo(shortName = "cos")
public abstract class PreProCosBuiltin extends PreProBuiltinNode {

@Specialization
public PreProConstant cos(PreProConstant constant) {
return new PreProConstant(applyCos(constant.timeSeries()));
}

@Specialization
public PreProMatrix3 cos(PreProMatrix3 matrix) {
return new PreProMatrix3(applyCos(matrix.timeSeries()));
}

@Specialization
public PreProMatrix4 cos(PreProMatrix4 matrix) {
return new PreProMatrix4(applyCos(matrix.timeSeries()));
}

@Specialization
public PreProMatrix cos(PreProMatrix matrix) {
return new PreProMatrix(applyCos(matrix.timeSeries()));
}

@Specialization
public PreProScalar cos(PreProScalar scalar) {
return new PreProScalar(applyCos(scalar.timeSeries()));
}

@Specialization
public PreProVector3 cos(PreProVector3 vector3) {
return new PreProVector3(applyCos(vector3.timeSeries()));
}


@Specialization
public PreProVector4 cos(PreProVector4 vector4) {
return new PreProVector4(applyCos(vector4.timeSeries()));
}

@Specialization
public PreProVector cos(PreProVector vector) {
return new PreProVector3(applyCos(vector.timeSeries()));
}

@TruffleBoundary
private static INDArray applyCos(INDArray original) {
return Transforms.cos(original, true);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.oracle.truffle.prepro.builtins;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.prepro.runtime.types.*;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.ops.transforms.Transforms;

@NodeInfo(shortName = "sin")
public abstract class PreProSinBuiltin extends PreProBuiltinNode {

@Specialization
public PreProConstant sin(PreProConstant constant) {
return new PreProConstant(applySin(constant.timeSeries()));
}

@Specialization
public PreProMatrix3 sin(PreProMatrix3 matrix) {
return new PreProMatrix3(applySin(matrix.timeSeries()));
}

@Specialization
public PreProMatrix4 sin(PreProMatrix4 matrix) {
return new PreProMatrix4(applySin(matrix.timeSeries()));
}

@Specialization
public PreProMatrix sin(PreProMatrix matrix) {
return new PreProMatrix(applySin(matrix.timeSeries()));
}

@Specialization
public PreProScalar sin(PreProScalar scalar) {
return new PreProScalar(applySin(scalar.timeSeries()));
}

@Specialization
public PreProVector3 sin(PreProVector3 vector3) {
return new PreProVector3(applySin(vector3.timeSeries()));
}


@Specialization
public PreProVector4 sin(PreProVector4 vector4) {
return new PreProVector4(applySin(vector4.timeSeries()));
}

@Specialization
public PreProVector sin(PreProVector vector) {
return new PreProVector3(applySin(vector.timeSeries()));
}

@TruffleBoundary
private static INDArray applySin(INDArray original){
return Transforms.sin(original, true);
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
package com.oracle.truffle.prepro.nodes.expression.builtin;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.prepro.nodes.PreProExpressionNode;

@NodeInfo(shortName = "exists")
public class PreProExistsNode extends PreProExpressionNode {

private final String text;
private final FrameSlot slot;

public PreProExistsNode(String text) {
this.text = text;
public PreProExistsNode(FrameSlot slot) {
this.slot = slot;
}

@Override
public Object executeGeneric(VirtualFrame frame) {
if (frame.getFrameDescriptor().findFrameSlot(text) != null) {
return 1;
}
return 0;
return ((slot != null) && frame.isObject(slot)) ? 1 : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,18 @@ public PreProExpressionNode createNumericLiteral(Token literalToken) {
}

public PreProExpressionNode createExistsExpression(Token nameToken) {
final PreProExistsNode preProExistsNode = new PreProExistsNode(nameToken.getText());
final String text = nameToken.getText();
oechsler marked this conversation as resolved.
Show resolved Hide resolved
LexicalScope lexicalScope = this.lexicalScope;
FrameSlot slot = null;
do {
if(lexicalScope.locals.containsKey(text)) {
slot = lexicalScope.locals.get(text);
break;
}
lexicalScope = lexicalScope.outer;
} while (lexicalScope != null);

final PreProExistsNode preProExistsNode = new PreProExistsNode(slot);
srcFromToken(preProExistsNode, nameToken);
return preProExistsNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.prepro.PreProLanguage;
import com.oracle.truffle.prepro.builtins.PreProBuiltinNode;
import com.oracle.truffle.prepro.builtins.PreProExportBuiltinFactory;
import com.oracle.truffle.prepro.builtins.PreProImportBuiltinFactory;
import com.oracle.truffle.prepro.builtins.PreProPrintBuiltin;
import com.oracle.truffle.prepro.builtins.PreProPrintBuiltinFactory;
import com.oracle.truffle.prepro.builtins.PreProThrowBuiltinFactory;
import com.oracle.truffle.prepro.builtins.*;
import com.oracle.truffle.prepro.nodes.PreProExpressionNode;
import com.oracle.truffle.prepro.nodes.PreProRootNode;
import com.oracle.truffle.prepro.nodes.local.PreProReadArgumentNode;
Expand Down Expand Up @@ -135,6 +130,8 @@ private void installBuiltins() {
installBuiltin(PreProThrowBuiltinFactory.getInstance());
installBuiltin(PreProImportBuiltinFactory.getInstance());
installBuiltin(PreProExportBuiltinFactory.getInstance());
installBuiltin(PreProSinBuiltinFactory.getInstance());
installBuiltin(PreProCosBuiltinFactory.getInstance());
}

private void installBuiltin(NodeFactory<? extends PreProBuiltinNode> factory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public int amountTimeElements() {
return ndArray.shape()[0];
}

@TruffleBoundary
public double getDoubleValue() {
return timeSeries().getDouble(0);
}
Expand Down Expand Up @@ -90,7 +91,7 @@ public PreProVector3 div(PreProVector3 right) {
@Override
@TruffleBoundary
public String toString() {
return timeSeries().shapeInfoToString();
return Double.toString(getDoubleValue());
oechsler marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
Expand Down
Loading