Skip to content

Commit

Permalink
[SMLJ-5] Foreign values, including record values based on the content…
Browse files Browse the repository at this point in the history
…s of a JDBC schema

Add "scott" and "foodmart" data sets based on embedded hsqldb databases.
  • Loading branch information
julianhyde committed Dec 3, 2019
1 parent 0588422 commit 2acb5ca
Show file tree
Hide file tree
Showing 18 changed files with 757 additions and 45 deletions.
24 changes: 24 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ License.
<top.dir>${project.basedir}</top.dir>

<!-- Component and plugin versions, in alphabetical order. -->
<calcite.version>1.21.0</calcite.version>
<checkstyle.version>7.8.2</checkstyle.version>
<findbugs.version>1.3.9</findbugs.version>
<!-- We support guava versions 19.0 to 27.1-jre. -->
<guava.version>21.0</guava.version>
<hamcrest.version>1.3</hamcrest.version>
<hsqldb.version>2.3.1</hsqldb.version>
<hydromatic-toolbox.version>0.3</hydromatic-toolbox.version>
<hydromatic-toolbox.version>0.3</hydromatic-toolbox.version>
<java-diff.version>1.1.2</java-diff.version>
Expand All @@ -93,6 +95,8 @@ License.
<maven-project-info-reports-plugin.version>2.9</maven-project-info-reports-plugin.version>
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
<maven-surefire-plugin.version>3.0.0-M3</maven-surefire-plugin.version>
<scott-data-hsqldb.version>0.1</scott-data-hsqldb.version>
<foodmart-data-hsqldb.version>0.4</foodmart-data-hsqldb.version>
<slf4j.version>1.7.25</slf4j.version>

<maven-javadoc-plugin.additionalOptions>-html5</maven-javadoc-plugin.additionalOptions>
Expand Down Expand Up @@ -132,6 +136,26 @@ License.
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>net.hydromatic</groupId>
<artifactId>foodmart-data-hsqldb</artifactId>
<version>${foodmart-data-hsqldb.version}</version>
</dependency>
<dependency>
<groupId>net.hydromatic</groupId>
<artifactId>scott-data-hsqldb</artifactId>
<version>${scott-data-hsqldb.version}</version>
</dependency>
<dependency>
<groupId>org.apache.calcite</groupId>
<artifactId>calcite-core</artifactId>
<version>${calcite.version}</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
Expand Down
7 changes: 4 additions & 3 deletions smlj
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ if [ ! -f target/classpath.txt ]; then
compile
fi

CP=target/classes
CP="${CP}:$(cat target/classpath.txt)"
CP="target/classes:\
target/test-classes:\
$(cat target/classpath.txt)"

VM_OPTS=
if [ "$cygwin" ]; then
Expand All @@ -50,6 +51,6 @@ fi

export JAVA_OPTS=-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

exec java $VM_OPTS -cp "${CP}" $JAVA_OPTS net.hydromatic.sml.Shell "$@"
exec java $VM_OPTS -cp "${CP}" $JAVA_OPTS net.hydromatic.sml.Shell --foreign='net.hydromatic.sml.DataSet$Dictionary' "$@"

# End smlj
20 changes: 14 additions & 6 deletions src/main/java/net/hydromatic/sml/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
*/
package net.hydromatic.sml;

import com.google.common.collect.ImmutableMap;

import net.hydromatic.sml.ast.AstNode;
import net.hydromatic.sml.compile.CompiledStatement;
import net.hydromatic.sml.compile.Compiles;
import net.hydromatic.sml.compile.Environment;
import net.hydromatic.sml.compile.Environments;
import net.hydromatic.sml.foreign.ForeignValue;
import net.hydromatic.sml.parse.ParseException;
import net.hydromatic.sml.parse.SmlParserImpl;
import net.hydromatic.sml.type.Binding;
Expand All @@ -42,19 +44,21 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/** Standard ML REPL. */
public class Main {
private final String[] args;
private final BufferedReader in;
private final PrintWriter out;
private final boolean echo;
private final Map<String, ForeignValue> valueMap;

/** Command-line entry point.
*
* @param args Command-line arguments */
public static void main(String[] args) {
final Main main = new Main(args, System.in, System.out);
final Main main = new Main(args, System.in, System.out, ImmutableMap.of());
try {
main.run();
} catch (Throwable e) {
Expand All @@ -64,16 +68,20 @@ public static void main(String[] args) {
}

/** Creates a Main. */
public Main(String[] args, InputStream in, PrintStream out) {
this(args, new InputStreamReader(in), new OutputStreamWriter(out));
public Main(String[] args, InputStream in, PrintStream out,
Map<String, ForeignValue> valueMap) {
this(args, new InputStreamReader(in), new OutputStreamWriter(out),
valueMap);
}

/** Creates a Main. */
public Main(String[] args, Reader in, Writer out) {
public Main(String[] args, Reader in, Writer out,
Map<String, ForeignValue> valueMap) {
this.args = args;
this.in = buffer(in);
this.out = buffer(out);
this.echo = Arrays.asList(args).contains("--echo");
this.valueMap = ImmutableMap.copyOf(valueMap);
}

private static PrintWriter buffer(Writer out) {
Expand All @@ -99,7 +107,7 @@ public void run() {
final TypeSystem typeSystem = new TypeSystem();
final BufferingReader in2 = new BufferingReader(in);
final SmlParserImpl parser = new SmlParserImpl(in2);
Environment env = Environments.empty();
Environment env = Compiles.createEnvironment(typeSystem, valueMap);
final List<String> lines = new ArrayList<>();
final List<Binding> bindings = new ArrayList<>();
for (;;) {
Expand Down
25 changes: 23 additions & 2 deletions src/main/java/net/hydromatic/sml/Shell.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
package net.hydromatic.sml;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import net.hydromatic.sml.ast.AstNode;
import net.hydromatic.sml.compile.CompileException;
import net.hydromatic.sml.compile.CompiledStatement;
import net.hydromatic.sml.compile.Compiles;
import net.hydromatic.sml.compile.Environment;
import net.hydromatic.sml.compile.Environments;
import net.hydromatic.sml.foreign.ForeignValue;
import net.hydromatic.sml.parse.ParseException;
import net.hydromatic.sml.parse.SmlParserImpl;
import net.hydromatic.sml.type.Binding;
Expand All @@ -48,9 +49,11 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/** Command shell for ML, powered by JLine3. */
public class Shell {
Expand All @@ -59,6 +62,7 @@ public class Shell {
private final Terminal terminal;
private final boolean banner;
private final boolean system;
private final ImmutableMap<String, ForeignValue> valueMap;
private boolean help;

/** Command-line entry point.
Expand All @@ -84,6 +88,23 @@ public Shell(List<String> args, InputStream in, OutputStream out)
this.echo = argList.contains("--echo");
this.help = argList.contains("--help");
this.system = !argList.contains("--system=false");
final ImmutableMap.Builder<String, ForeignValue> valueMapBuilder =
ImmutableMap.builder();
for (String arg : args) {
if (arg.startsWith("--foreign=")) {
final String className = arg.substring("--foreign=".length());
try {
final Class<?> aClass = Class.forName(className);
valueMapBuilder.putAll((Map<String, ForeignValue>)
aClass.getConstructor().newInstance());
} catch (InstantiationException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException
| ClassNotFoundException e) {
e.printStackTrace();
}
}
}
this.valueMap = valueMapBuilder.build();

final TerminalBuilder builder = TerminalBuilder.builder();
builder.streams(in, out);
Expand Down Expand Up @@ -179,7 +200,7 @@ public void run() {

pause();
final TypeSystem typeSystem = new TypeSystem();
Environment env = Environments.empty();
Environment env = Compiles.createEnvironment(typeSystem, valueMap);
final StringBuilder buf = new StringBuilder();
final List<String> lines = new ArrayList<>();
final List<Binding> bindings = new ArrayList<>();
Expand Down
19 changes: 1 addition & 18 deletions src/main/java/net/hydromatic/sml/compile/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ public Type getType() {

public void eval(Environment env, List<String> output,
List<Binding> bindings) {
final EvalEnvHolder evalEnvs = new EvalEnvHolder(Codes.emptyEnv());
env.forEachValue(evalEnvs::add);
final EvalEnv evalEnv = evalEnvs.evalEnv;
final EvalEnv evalEnv = Codes.emptyEnvWith(env);
for (Action entry : actions) {
entry.apply(output, bindings, evalEnv);
}
Expand Down Expand Up @@ -557,21 +555,6 @@ public Object eval(EvalEnv env) {
}
}

/** Contains a {@link EvalEnv} and adds to it by calling
* {@link Codes#add}. */
private static class EvalEnvHolder {
private EvalEnv evalEnv;

EvalEnvHolder(EvalEnv evalEnv) {
this.evalEnv = Objects.requireNonNull(evalEnv);
}

public EvalEnvHolder add(String name, Object value) {
evalEnv = Codes.add(evalEnv, name, value);
return this;
}
}

/** A comparable singleton list.
*
* @param <E> Element type */
Expand Down
26 changes: 24 additions & 2 deletions src/main/java/net/hydromatic/sml/compile/Compiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@
import net.hydromatic.sml.ast.AstNode;
import net.hydromatic.sml.ast.Pos;
import net.hydromatic.sml.eval.Codes;
import net.hydromatic.sml.foreign.ForeignValue;
import net.hydromatic.sml.type.Binding;
import net.hydromatic.sml.type.TypeSystem;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static net.hydromatic.sml.ast.AstBuilder.ast;

/** Helpers for {@link Compiler} and {@link TypeResolver}. */
Expand All @@ -34,12 +40,28 @@ public abstract class Compiles {
* expression to a form that can more easily be compiled.
*
* <p>Used for testing. */
public static TypeResolver.Resolved validateExpression(Ast.Exp exp) {
public static TypeResolver.Resolved validateExpression(Ast.Exp exp,
Map<String, ForeignValue> valueMap) {
final TypeSystem typeSystem = new TypeSystem();
final Environment env = Environments.empty();
final Environment env = createEnvironment(typeSystem, valueMap);
return TypeResolver.deduceType(env, toValDecl(exp), typeSystem);
}

/** Creates an environment containing the given foreign values. */
public static Environment createEnvironment(TypeSystem typeSystem,
Map<String, ForeignValue> valueMap) {
return Environments.empty()
.bindAll(bindings(typeSystem, valueMap));
}

private static Iterable<Binding> bindings(TypeSystem typeSystem,
Map<String, ForeignValue> map) {
final List<Binding> bindings = new ArrayList<>();
map.forEach((name, value) ->
bindings.add(new Binding(name, value.type(typeSystem), value.value())));
return bindings;
}

/**
* Validates and compiles a statement (expression or declaration), and
* compiles it to code that can be evaluated by the interpreter.
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/hydromatic/sml/compile/Pretty.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package net.hydromatic.sml.compile;

import net.hydromatic.sml.foreign.RelList;
import net.hydromatic.sml.type.ListType;
import net.hydromatic.sml.type.PrimitiveType;
import net.hydromatic.sml.type.RecordType;
Expand Down Expand Up @@ -112,6 +113,10 @@ private static StringBuilder pretty2(@Nonnull StringBuilder buf,
(ListType) type;
//noinspection unchecked
list = (List) value;
if (list instanceof RelList) {
// Do not attempt to print the elements of a foreign list. It might be huge.
return buf.append("<relation>");
}
buf.append("[");
start = buf.length();
for (Object o : list) {
Expand Down
20 changes: 14 additions & 6 deletions src/main/java/net/hydromatic/sml/eval/Codes.java
Original file line number Diff line number Diff line change
Expand Up @@ -754,17 +754,25 @@ private static Applicable collate(Applicable comparator) {

/** Creates an empty evaluation environment. */
public static EvalEnv emptyEnv() {
final EvalEnv env = new EvalEnv();
final EvalEnv evalEnv = new EvalEnv();
BUILT_IN_VALUES.forEach((key, value) -> {
env.valueMap.put(key.mlName, value);
evalEnv.valueMap.put(key.mlName, value);
if (key.alias != null) {
env.valueMap.put(key.alias, value);
evalEnv.valueMap.put(key.alias, value);
}
});
assert env.valueMap.keySet().containsAll(BuiltIn.BY_ML_NAME.keySet())
assert evalEnv.valueMap.keySet().containsAll(BuiltIn.BY_ML_NAME.keySet())
: "no implementation for "
+ minus(BuiltIn.BY_ML_NAME.keySet(), env.valueMap.keySet());
return env;
+ minus(BuiltIn.BY_ML_NAME.keySet(), evalEnv.valueMap.keySet());
return evalEnv;
}

/** Creates an evaluation environment that contains the bound values from a
* compilation environment. */
public static EvalEnv emptyEnvWith(Environment env) {
final EvalEnv evalEnv = emptyEnv();
env.forEachValue(evalEnv.valueMap::put);
return evalEnv;
}

/** Creates a compilation environment. */
Expand Down
Loading

0 comments on commit 2acb5ca

Please sign in to comment.