diff --git a/src/main/java/de/neemann/digital/hdl/hgs/Context.java b/src/main/java/de/neemann/digital/hdl/hgs/Context.java index 8c629f2d4..bfb2d3532 100644 --- a/src/main/java/de/neemann/digital/hdl/hgs/Context.java +++ b/src/main/java/de/neemann/digital/hdl/hgs/Context.java @@ -6,8 +6,8 @@ package de.neemann.digital.hdl.hgs; import de.neemann.digital.hdl.hgs.function.Func; -import de.neemann.digital.hdl.hgs.function.FuncAdapter; import de.neemann.digital.hdl.hgs.function.Function; +import de.neemann.digital.hdl.hgs.function.InnerFunction; import java.util.ArrayList; import java.util.HashMap; @@ -121,7 +121,7 @@ public class Context { * @param func the function * @return this for chained calls */ - public Context addFunc(String name, Function func) { + public Context addFunc(String name, InnerFunction func) { return setVar(name, func); } @@ -188,49 +188,49 @@ public class Context { * @return the function * @throws HGSEvalException HGSEvalException */ - public FuncAdapter getFunction(String funcName) throws HGSEvalException { + public Function getFunction(String funcName) throws HGSEvalException { Object fObj = getVar(funcName); - if (fObj instanceof FuncAdapter) - return (FuncAdapter) fObj; + if (fObj instanceof Function) + return (Function) fObj; else throw new HGSEvalException("Variable '" + funcName + "' is not a function"); } - private static final class FunctionPrint extends Function { + private static final class FunctionPrint extends InnerFunction { private FunctionPrint() { super(-1); } @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { for (Expression arg : args) c.print(arg.value(c).toString()); return null; } } - private static final class FunctionPrintf extends Function { + private static final class FunctionPrintf extends InnerFunction { private FunctionPrintf() { super(-1); } @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { c.print(format(c, args)); return null; } } - private static final class FunctionFormat extends Function { + private static final class FunctionFormat extends InnerFunction { private FunctionFormat() { super(-1); } @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { return format(c, args); } } @@ -246,14 +246,14 @@ public class Context { return String.format(Value.toString(args.get(0).value(c)), eval.toArray()); } - private static final class FunctionIsPresent extends Function { + private static final class FunctionIsPresent extends InnerFunction { private FunctionIsPresent() { super(1); } @Override - public Object callWithExpressions(Context c, ArrayList args) { + public Object call(Context c, ArrayList args) { try { args.get(0).value(c); return true; @@ -263,7 +263,7 @@ public class Context { } } - private static final class FunctionPanic extends FuncAdapter { + private static final class FunctionPanic extends Function { private FunctionPanic() { super(1); } diff --git a/src/main/java/de/neemann/digital/hdl/hgs/function/FirstClassFunctionCall.java b/src/main/java/de/neemann/digital/hdl/hgs/function/FirstClassFunctionCall.java index 78e80cad5..0a24174fe 100644 --- a/src/main/java/de/neemann/digital/hdl/hgs/function/FirstClassFunctionCall.java +++ b/src/main/java/de/neemann/digital/hdl/hgs/function/FirstClassFunctionCall.java @@ -9,9 +9,9 @@ import de.neemann.digital.hdl.hgs.Context; import de.neemann.digital.hdl.hgs.HGSEvalException; /** - * A call to a first class function + * A call to a first class function. */ -public final class FirstClassFunctionCall extends FuncAdapter { +public final class FirstClassFunctionCall extends Function { private final FirstClassFunction func; private final Context capturedContext; diff --git a/src/main/java/de/neemann/digital/hdl/hgs/function/Func.java b/src/main/java/de/neemann/digital/hdl/hgs/function/Func.java index 23c0ad52d..34b5228bb 100644 --- a/src/main/java/de/neemann/digital/hdl/hgs/function/Func.java +++ b/src/main/java/de/neemann/digital/hdl/hgs/function/Func.java @@ -11,7 +11,7 @@ import de.neemann.digital.hdl.hgs.HGSEvalException; * A function. * Can be used to define a function by a lambda expression. */ -public class Func extends FuncAdapter { +public class Func extends Function { private final Interface func; /** diff --git a/src/main/java/de/neemann/digital/hdl/hgs/function/FuncAdapter.java b/src/main/java/de/neemann/digital/hdl/hgs/function/FuncAdapter.java deleted file mode 100644 index 5449d3c17..000000000 --- a/src/main/java/de/neemann/digital/hdl/hgs/function/FuncAdapter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018 Helmut Neemann. - * Use of this source code is governed by the GPL v3 license - * that can be found in the LICENSE file. - */ -package de.neemann.digital.hdl.hgs.function; - -import de.neemann.digital.hdl.hgs.Context; -import de.neemann.digital.hdl.hgs.HGSEvalException; -import de.neemann.digital.hdl.hgs.Expression; - -import java.util.ArrayList; - -/** - * Simple function adapter to implement a function with already evaluated arguments - */ -public abstract class FuncAdapter extends Function { - /** - * Creates a new function - * - * @param argCount the number of arguments - */ - public FuncAdapter(int argCount) { - super(argCount); - } - - @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { - Object[] data = new Object[args.size()]; - for (int i = 0; i < args.size(); i++) - data[i] = args.get(i).value(c); - return f(data); - } - - /** - * Evaluates this function. - * - * @param args the arguments - * @return the result - * @throws HGSEvalException HGSEvalException - */ - protected abstract Object f(Object... args) throws HGSEvalException; - - /** - * Use this method to call the function from your java code. - * - * @param args the arguments of this function - * @return the function result - * @throws HGSEvalException HGSEvalException - */ - public Object call(Object... args) throws HGSEvalException { - if (getArgCount() >= 0 && getArgCount() != args.length) - throw new HGSEvalException("wrong number of arguments! found: " + args.length + ", expected: " + getArgCount()); - return f(args); - } - -} diff --git a/src/main/java/de/neemann/digital/hdl/hgs/function/Function.java b/src/main/java/de/neemann/digital/hdl/hgs/function/Function.java index 6054c43ae..65f51dd55 100644 --- a/src/main/java/de/neemann/digital/hdl/hgs/function/Function.java +++ b/src/main/java/de/neemann/digital/hdl/hgs/function/Function.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Helmut Neemann + * Copyright (c) 2018 Helmut Neemann. * Use of this source code is governed by the GPL v3 license * that can be found in the LICENSE file. */ @@ -12,35 +12,47 @@ import de.neemann.digital.hdl.hgs.Expression; import java.util.ArrayList; /** - * A simple mathematical function + * Class to implement a function with already evaluated arguments. + * Its the easiest way to implement a pure function, which means a mathematical function + * which only uses the arguments given to the function. */ -public abstract class Function { - - private final int argCount; - +public abstract class Function extends InnerFunction { /** * Creates a new function * * @param argCount the number of arguments */ public Function(int argCount) { - this.argCount = argCount; + super(argCount); + } + + @Override + public Object call(Context c, ArrayList args) throws HGSEvalException { + Object[] data = new Object[args.size()]; + for (int i = 0; i < args.size(); i++) + data[i] = args.get(i).value(c); + return f(data); } /** - * @return the number of required arguments - */ - public int getArgCount() { - return argCount; - } - - /** - * Calculates the value + * Use this method to call the function from your java code. * - * @param c the context - * @param args the arguments - * @return the value + * @param args the arguments of this function + * @return the function result * @throws HGSEvalException HGSEvalException */ - public abstract Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException; + public Object call(Object... args) throws HGSEvalException { + if (getArgCount() >= 0 && getArgCount() != args.length) + throw new HGSEvalException("wrong number of arguments! found: " + args.length + ", expected: " + getArgCount()); + return f(args); + } + + /** + * Evaluates this function. + * + * @param args the arguments + * @return the result + * @throws HGSEvalException HGSEvalException + */ + protected abstract Object f(Object... args) throws HGSEvalException; } diff --git a/src/main/java/de/neemann/digital/hdl/hgs/function/InnerFunction.java b/src/main/java/de/neemann/digital/hdl/hgs/function/InnerFunction.java new file mode 100644 index 000000000..8d9fe5566 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/hgs/function/InnerFunction.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Helmut Neemann + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.hdl.hgs.function; + +import de.neemann.digital.hdl.hgs.Context; +import de.neemann.digital.hdl.hgs.HGSEvalException; +import de.neemann.digital.hdl.hgs.Expression; + +import java.util.ArrayList; + +/** + * Description of a basic function. + * The arguments to the function are expressions not yet evaluated. + * In most cases its easier to override the {@link Function} class. + */ +public abstract class InnerFunction { + + private final int argCount; + + /** + * Creates a new function + * + * @param argCount the number of arguments + */ + public InnerFunction(int argCount) { + this.argCount = argCount; + } + + /** + * @return the number of required arguments + */ + public int getArgCount() { + return argCount; + } + + /** + * Calculates the value. + * Don't call this function from your java code! + * + * @param c the context + * @param args the arguments + * @return the value + * @throws HGSEvalException HGSEvalException + */ + public abstract Object call(Context c, ArrayList args) throws HGSEvalException; +} diff --git a/src/main/java/de/neemann/digital/hdl/hgs/refs/ReferenceToFunc.java b/src/main/java/de/neemann/digital/hdl/hgs/refs/ReferenceToFunc.java index 45fd0b24a..6187275f6 100644 --- a/src/main/java/de/neemann/digital/hdl/hgs/refs/ReferenceToFunc.java +++ b/src/main/java/de/neemann/digital/hdl/hgs/refs/ReferenceToFunc.java @@ -8,7 +8,7 @@ package de.neemann.digital.hdl.hgs.refs; import de.neemann.digital.hdl.hgs.Context; import de.neemann.digital.hdl.hgs.HGSEvalException; import de.neemann.digital.hdl.hgs.Expression; -import de.neemann.digital.hdl.hgs.function.Function; +import de.neemann.digital.hdl.hgs.function.InnerFunction; import java.util.ArrayList; @@ -38,11 +38,11 @@ public class ReferenceToFunc implements Reference { @Override public Object get(Context context) throws HGSEvalException { Object funcObj = parent.get(context); - if (funcObj instanceof Function) { - final Function func = (Function) funcObj; + if (funcObj instanceof InnerFunction) { + final InnerFunction func = (InnerFunction) funcObj; if (func.getArgCount() >= 0 && func.getArgCount() != args.size()) throw new HGSEvalException("wrong number of arguments! found: " + args.size() + ", expected: " + func.getArgCount()); - return func.callWithExpressions(context, args); + return func.call(context, args); } throw new HGSEvalException("Value is not a function!"); } diff --git a/src/main/java/de/neemann/digital/hdl/vhdl/lib/VHDLTemplate.java b/src/main/java/de/neemann/digital/hdl/vhdl/lib/VHDLTemplate.java index c3820adb4..2ed494918 100644 --- a/src/main/java/de/neemann/digital/hdl/vhdl/lib/VHDLTemplate.java +++ b/src/main/java/de/neemann/digital/hdl/vhdl/lib/VHDLTemplate.java @@ -6,8 +6,8 @@ package de.neemann.digital.hdl.vhdl.lib; import de.neemann.digital.hdl.hgs.*; -import de.neemann.digital.hdl.hgs.function.FuncAdapter; import de.neemann.digital.hdl.hgs.function.Function; +import de.neemann.digital.hdl.hgs.function.InnerFunction; import de.neemann.digital.hdl.model.HDLException; import de.neemann.digital.hdl.model.HDLNode; import de.neemann.digital.hdl.model.Port; @@ -34,25 +34,25 @@ public class VHDLTemplate implements VHDLEntity { .addFunc("type", new FunctionType()) .addFunc("genericType", new FunctionGenericType()) .addFunc("value", new FunctionValue()) - .addFunc("beginGenericPort", new Function(0) { + .addFunc("beginGenericPort", new InnerFunction(0) { @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { c.setVar("portStartPos", c.length()); return null; } }) - .addFunc("endGenericPort", new Function(0) { + .addFunc("endGenericPort", new InnerFunction(0) { @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { int start = Value.toInt(c.getVar("portStartPos")); String portDecl = c.toString().substring(start); c.setVar("portDecl", portDecl); return null; } }) - .addFunc("registerGeneric", new Function(-1) { + .addFunc("registerGeneric", new InnerFunction(-1) { @Override - public Object callWithExpressions(Context c, ArrayList args) throws HGSEvalException { + public Object call(Context c, ArrayList args) throws HGSEvalException { List generics; if (c.contains("generics")) generics = (List) c.getVar("generics"); @@ -239,7 +239,7 @@ public class VHDLTemplate implements VHDLEntity { } } - private final static class FunctionType extends FuncAdapter { + private final static class FunctionType extends Function { private FunctionType() { super(1); @@ -258,7 +258,7 @@ public class VHDLTemplate implements VHDLEntity { } - private final static class FunctionGenericType extends FuncAdapter { + private final static class FunctionGenericType extends Function { private FunctionGenericType() { super(1); @@ -275,7 +275,7 @@ public class VHDLTemplate implements VHDLEntity { } - private final static class FunctionZero extends FuncAdapter { + private final static class FunctionZero extends Function { private FunctionZero() { super(1); @@ -292,7 +292,7 @@ public class VHDLTemplate implements VHDLEntity { } - private final static class FunctionValue extends FuncAdapter { + private final static class FunctionValue extends Function { /** * Creates a new function */ diff --git a/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java b/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java index c53d4b596..6e3fe84e9 100644 --- a/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java +++ b/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java @@ -5,8 +5,7 @@ */ package de.neemann.digital.hdl.hgs; -import de.neemann.digital.hdl.hgs.function.FirstClassFunction; -import de.neemann.digital.hdl.hgs.function.FuncAdapter; +import de.neemann.digital.hdl.hgs.function.Function; import de.neemann.digital.integration.FileScanner; import de.neemann.digital.integration.Resources; import junit.framework.TestCase; @@ -254,7 +253,7 @@ public class ParserTest extends TestCase { public void testAddFunction() throws IOException, ParserException, HGSEvalException { Statement s = new Parser("a : in ;").parse(); - Context funcs = new Context().setVar("type", new FuncAdapter(1) { + Context funcs = new Context().setVar("type", new Function(1) { @Override protected Object f(Object... args) throws HGSEvalException { int n = Value.toInt(args[0]); @@ -278,7 +277,7 @@ public class ParserTest extends TestCase { flag = 0; Statement s = new Parser("a : in ;").parse(); - Context c = new Context().addFunc("type", new FuncAdapter(1) { + Context c = new Context().addFunc("type", new Function(1) { @Override protected Object f(Object... args) throws HGSEvalException { flag = Value.toInt(args[0]); @@ -303,8 +302,8 @@ public class ParserTest extends TestCase { Parser p = new Parser(""); p.parse(); Object fObj = p.getStaticContext().getVar("f"); - assertTrue(fObj instanceof FuncAdapter); - FuncAdapter f = (FuncAdapter) fObj; + assertTrue(fObj instanceof Function); + Function f = (Function) fObj; assertEquals(11L, f.call(3)); } @@ -331,13 +330,13 @@ public class ParserTest extends TestCase { public void testFirstClassFunctionLambda() throws IOException, ParserException, HGSEvalException { Context c = exec(""); - FuncAdapter f = c.getFunction("f"); + Function f = c.getFunction("f"); assertEquals(6L,f.call(1)); assertEquals(7L,f.call(2)); c = exec(""); - FuncAdapter a = c.getFunction("a"); - FuncAdapter b = c.getFunction("b"); + Function a = c.getFunction("a"); + Function b = c.getFunction("b"); assertEquals(4L,a.call(2)); assertEquals(6L,a.call(3)); assertEquals(10L,b.call(2));