Skip to content

Commit

Permalink
Improved RDS parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
vruusmann committed Jul 29, 2024
1 parent 598789e commit fa85aed
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 14 deletions.
56 changes: 56 additions & 0 deletions pmml-rexp/src/main/java/org/jpmml/rexp/REnvironment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Villu Ruusmann
*
* This file is part of JPMML-R
*
* JPMML-R is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JPMML-R is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with JPMML-R. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpmml.rexp;

abstract
public class REnvironment extends RExp {

private RPair variables = null;


REnvironment(){
super(null);
}

public RExp findVariable(String name){
RPair variable = getVariables();

while(variable != null){

if(variable.tagEquals(name)){
return variable.getValue();
}

variable = variable.getNext();
}

return null;
}

public RPair getVariables(){
return this.variables;
}

void setVariables(RPair variables){
this.variables = variables;
}

public static final REnvironment EMPTY = new REnvironment(){
};
}
2 changes: 1 addition & 1 deletion pmml-rexp/src/main/java/org/jpmml/rexp/RExp.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public RPair getAttributes(){
return this.attributes;
}

private void setAttributes(RPair attributes){
void setAttributes(RPair attributes){
this.attributes = attributes;
}
}
46 changes: 33 additions & 13 deletions pmml-rexp/src/main/java/org/jpmml/rexp/RExpParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import com.google.common.io.ByteStreams;
Expand All @@ -34,6 +36,8 @@ public class RExpParser {

private RDataInput input = null;

private Map<RSymbol, REnvironment> namespaces = new LinkedHashMap<>();

private List<RExp> referenceTable = new ArrayList<>();


Expand Down Expand Up @@ -106,13 +110,13 @@ private RExp readRExp() throws IOException {
case SerializationTypes.BASEENVSXP:
return null; // XXX
case SerializationTypes.EMPTYENVSXP:
return null; // XXX
return REnvironment.EMPTY;
case SerializationTypes.NAMESPACESXP:
return readNamespace();
case SerializationTypes.BASENAMESPACESXP:
return null; // XXX
case SerializationTypes.MISSINGARGSXP:
return null; // XXX
return RSymbol.MISSING_ARG;
case SerializationTypes.UNBOUNDVALUESXP:
return null; // XXX
case SerializationTypes.GLOBALENVSXP:
Expand Down Expand Up @@ -182,22 +186,27 @@ private RExp readClosure(int flags) throws IOException {
return new RClosure(attributes, environment, parameters, body);
}

private RExp readEnvironment(int flags) throws IOException {
RExp rexp = null;
private REnvironment readEnvironment(int flags) throws IOException {
REnvironment environment = new REnvironment(){
};

readInt();

// "MUST register before filling in"
this.referenceTable.add(rexp);
this.referenceTable.add(environment);

// "Now fill it in"
RExp parent = readRExp();
RPair frame = (RPair)readRExp();
RExp hashtab = readRExp();

environment.setVariables(frame);

RPair attributes = (RPair)readRExp();

return rexp;
environment.setAttributes(attributes);

return environment;
}

private RExp readPromise(int flags) throws IOException {
Expand Down Expand Up @@ -343,16 +352,18 @@ private RExp readBytecode(int flags) throws IOException {
}

private RExp readExternalPointer(int flags) throws IOException {
RExp rexp = null;
RExternalPtr externalPtr = new RExternalPtr(null);

this.referenceTable.add(rexp);
this.referenceTable.add(externalPtr);

RExp protected_ = readRExp();
RExp tag = readRExp();

readAttributes(flags);
RPair attributes = readAttributes(flags);

externalPtr.setAttributes(attributes);

return rexp;
return externalPtr;
}

private RRaw readRaw(int flags) throws IOException {
Expand Down Expand Up @@ -476,11 +487,20 @@ private RExp readNamespace() throws IOException {
throw new UnsupportedOperationException();
}

readStringVector(flags);
RStringVector name = readStringVector(flags);

this.referenceTable.add(null);
RSymbol symbol = new RSymbol(name.getValue(0));

return null;
REnvironment namespace = this.namespaces.get(symbol);
if(namespace == null){
namespace = new REnvironment(){};

this.namespaces.put(symbol, namespace);
}

this.referenceTable.add(namespace);

return namespace;
}

private RExp readReference(int flags) throws IOException {
Expand Down
26 changes: 26 additions & 0 deletions pmml-rexp/src/main/java/org/jpmml/rexp/RExternalPtr.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Villu Ruusmann
*
* This file is part of JPMML-R
*
* JPMML-R is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JPMML-R is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with JPMML-R. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpmml.rexp;

public class RExternalPtr extends RExp {

public RExternalPtr(RPair attributes){
super(attributes);
}
}
60 changes: 60 additions & 0 deletions pmml-rexp/src/main/java/org/jpmml/rexp/RSymbol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 Villu Ruusmann
*
* This file is part of JPMML-R
*
* JPMML-R is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JPMML-R is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with JPMML-R. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jpmml.rexp;

import java.util.Objects;

public class RSymbol extends RExp {

private String value = null;


public RSymbol(String value){
super(null);

setValue(value);
}

@Override
public int hashCode(){
return Objects.hashCode(this.getValue());
}

@Override
public boolean equals(Object object){

if(object instanceof RSymbol){
RSymbol that = (RSymbol)object;

return Objects.equals(this.getValue(), that.getValue());
}

return false;
}

public String getValue(){
return this.value;
}

private void setValue(String value){
this.value = Objects.requireNonNull(value);
}

public static final RSymbol MISSING_ARG = new RSymbol("");
}

0 comments on commit fa85aed

Please sign in to comment.