mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 17:04:42 -04:00
simplification of first class functions
This commit is contained in:
parent
70a1a8bc9d
commit
9f9d564bfa
@ -5,6 +5,11 @@
|
||||
*/
|
||||
package de.neemann.digital.hdl.hgs;
|
||||
|
||||
import de.neemann.digital.hdl.hgs.function.Func;
|
||||
import de.neemann.digital.hdl.hgs.function.FunctionFormat;
|
||||
import de.neemann.digital.hdl.hgs.function.FunctionIsSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@ -14,13 +19,12 @@ public class Context {
|
||||
private final Context parent;
|
||||
private final StringBuilder code;
|
||||
private HashMap<String, Object> map;
|
||||
private int recordStart = 0;
|
||||
|
||||
/**
|
||||
* Creates a new context
|
||||
*/
|
||||
public Context() {
|
||||
this(null, new StringBuilder());
|
||||
this(null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,19 +33,27 @@ public class Context {
|
||||
* @param parent the parent context
|
||||
*/
|
||||
public Context(Context parent) {
|
||||
this(parent, null);
|
||||
this(parent, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new context
|
||||
*
|
||||
* @param parent the parent context
|
||||
* @param code the code
|
||||
* @param parent the parent context
|
||||
* @param enablePrint enables the print, if false, the printing goes to the parent of this context
|
||||
*/
|
||||
public Context(Context parent, StringBuilder code) {
|
||||
public Context(Context parent, boolean enablePrint) {
|
||||
this.parent = parent;
|
||||
this.code = code;
|
||||
if (enablePrint)
|
||||
this.code = new StringBuilder();
|
||||
else
|
||||
this.code = null;
|
||||
map = new HashMap<>();
|
||||
// some function which are always present
|
||||
map.put("format", new FunctionFormat());
|
||||
map.put("isset", new FunctionIsSet());
|
||||
map.put("newMap", new Func(0, args -> new HashMap()));
|
||||
map.put("newList", new Func(0, args -> new ArrayList()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,9 +116,8 @@ public class Context {
|
||||
public Context print(String str) {
|
||||
if (code != null)
|
||||
code.append(str);
|
||||
else {
|
||||
else
|
||||
parent.print(str);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -115,7 +126,7 @@ public class Context {
|
||||
if (code != null)
|
||||
return code.toString();
|
||||
else
|
||||
return map.toString();
|
||||
return parent.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,8 @@
|
||||
*/
|
||||
package de.neemann.digital.hdl.hgs;
|
||||
|
||||
import de.neemann.digital.hdl.hgs.function.Function;
|
||||
|
||||
/**
|
||||
* Simple expression
|
||||
* Created by Helmut.Neemann on 02.12.2016.
|
||||
@ -73,6 +75,19 @@ public interface Expression {
|
||||
throw new EvalException("must be a string, is a " + value.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value to a function
|
||||
*
|
||||
* @param value the value to convert
|
||||
* @return the function
|
||||
* @throws EvalException EvalException
|
||||
*/
|
||||
static Function toFunc(Object value) throws EvalException {
|
||||
if (value instanceof Function)
|
||||
return (Function) value;
|
||||
throw new EvalException("must be a function, is a " + value.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two values
|
||||
*
|
||||
|
@ -6,19 +6,13 @@
|
||||
package de.neemann.digital.hdl.hgs;
|
||||
|
||||
import de.neemann.digital.core.Bits;
|
||||
import de.neemann.digital.hdl.hgs.function.Function;
|
||||
import de.neemann.digital.hdl.hgs.function.FunctionFormat;
|
||||
import de.neemann.digital.hdl.hgs.function.FunctionIsSet;
|
||||
import de.neemann.digital.hdl.hgs.refs.Reference;
|
||||
import de.neemann.digital.hdl.hgs.refs.ReferenceToArray;
|
||||
import de.neemann.digital.hdl.hgs.refs.ReferenceToStruct;
|
||||
import de.neemann.digital.hdl.hgs.refs.ReferenceToVar;
|
||||
import de.neemann.digital.hdl.hgs.function.FirstClassFunction;
|
||||
import de.neemann.digital.hdl.hgs.refs.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static de.neemann.digital.hdl.hgs.Tokenizer.Token.*;
|
||||
|
||||
@ -28,7 +22,6 @@ import static de.neemann.digital.hdl.hgs.Tokenizer.Token.*;
|
||||
public class Parser {
|
||||
|
||||
private final Tokenizer tok;
|
||||
private HashMap<String, Function> functions;
|
||||
private Context staticContext;
|
||||
|
||||
/**
|
||||
@ -47,44 +40,13 @@ public class Parser {
|
||||
*/
|
||||
public Parser(Reader reader) {
|
||||
tok = new Tokenizer(reader);
|
||||
functions = new HashMap<>();
|
||||
addFunction("format", new FunctionFormat());
|
||||
|
||||
addFunction("isset", new FunctionIsSet());
|
||||
|
||||
addFunction("newList", new Function(0) {
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
});
|
||||
|
||||
addFunction("newMap", new Function(0) {
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
});
|
||||
|
||||
staticContext = new Context();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new function to the parser
|
||||
*
|
||||
* @param name the name
|
||||
* @param function the function
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public Parser addFunction(String name, Function function) {
|
||||
functions.put(name, function);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given template source
|
||||
*
|
||||
* @return the Statemant to execute
|
||||
* @return the Statement to execute
|
||||
* @throws IOException IOException
|
||||
* @throws ParserException ParserException
|
||||
*/
|
||||
@ -136,13 +98,8 @@ public class Parser {
|
||||
} else if (isToken(ADD)) {
|
||||
expect(ADD);
|
||||
return c -> ref.set(c, Expression.add(ref.get(c), 1));
|
||||
} else if (isToken(OPEN)) {
|
||||
ArrayList<Expression> args = parseArgList();
|
||||
expect(SEMICOLON);
|
||||
if (ref instanceof ReferenceToVar) {
|
||||
return findFunctionStatement(((ReferenceToVar) ref).getName(), args);
|
||||
} else
|
||||
throw newParserException("method call on composite var");
|
||||
} else if (isToken(SEMICOLON)) {
|
||||
return ref::get;
|
||||
} else
|
||||
throw newUnexpectedToken(tok.next());
|
||||
} else if (isToken(CODEEND)) {
|
||||
@ -223,6 +180,9 @@ public class Parser {
|
||||
Expression index = parseExpression();
|
||||
expect(CLOSEDSQUARE);
|
||||
r = new ReferenceToArray(r, index);
|
||||
} else if (isToken(OPEN)) {
|
||||
ArrayList<Expression> args = parseArgList();
|
||||
r = new ReferenceToFunc(r, args);
|
||||
} else if (isToken(DOT)) {
|
||||
expect(IDENT);
|
||||
r = new ReferenceToStruct(r, tok.getIdent());
|
||||
@ -414,13 +374,8 @@ public class Parser {
|
||||
switch (t) {
|
||||
case IDENT:
|
||||
String name = tok.getIdent();
|
||||
if (isToken(OPEN)) {
|
||||
ArrayList<Expression> args = parseArgList();
|
||||
return findFunction(name, args);
|
||||
} else {
|
||||
Reference r = parseReference(name);
|
||||
return r::get;
|
||||
}
|
||||
Reference r = parseReference(name);
|
||||
return r::get;
|
||||
case NUMBER:
|
||||
long num = convToLong(tok.getIdent());
|
||||
return c -> num;
|
||||
@ -461,38 +416,4 @@ public class Parser {
|
||||
return new FirstClassFunction(args, st);
|
||||
}
|
||||
|
||||
private Expression findFunction(String name, ArrayList<Expression> args) throws ParserException {
|
||||
Function f = functions.get(name);
|
||||
if (f != null) {
|
||||
if (f.getArgCount() != args.size() && f.getArgCount() >= 0)
|
||||
throw newParserException("function " + name + " needs " + f.getArgCount() + "arguments, but found " + args.size());
|
||||
return c -> f.calcValue(c, args);
|
||||
} else {
|
||||
return c -> {
|
||||
Object func = c.getVar(name);
|
||||
if (func instanceof FirstClassFunction)
|
||||
return ((FirstClassFunction) func).calcValue(c, args);
|
||||
else
|
||||
throw new EvalException("first class function " + name + " not found");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private Statement findFunctionStatement(String name, ArrayList<Expression> args) throws ParserException {
|
||||
Function f = functions.get(name);
|
||||
if (f != null) {
|
||||
if (f.getArgCount() != args.size() && f.getArgCount() >= 0)
|
||||
throw newParserException("function " + name + " needs " + f.getArgCount() + "arguments, but found " + args.size());
|
||||
return c -> f.calcValue(c, args);
|
||||
} else {
|
||||
return c -> {
|
||||
Object func = c.getVar(name);
|
||||
if (func instanceof FirstClassFunction)
|
||||
((FirstClassFunction) func).calcValue(c, args);
|
||||
else
|
||||
throw new EvalException("first class function " + name + " not found");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,14 +3,18 @@
|
||||
* 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;
|
||||
package de.neemann.digital.hdl.hgs.function;
|
||||
|
||||
import de.neemann.digital.hdl.hgs.Context;
|
||||
import de.neemann.digital.hdl.hgs.EvalException;
|
||||
import de.neemann.digital.hdl.hgs.Statement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* callable first class function
|
||||
*/
|
||||
public class FirstClassFunction {
|
||||
public class FirstClassFunction extends FuncAdapter {
|
||||
private final ArrayList<String> args;
|
||||
private final Statement st;
|
||||
|
||||
@ -21,6 +25,7 @@ public class FirstClassFunction {
|
||||
* @param st the function body
|
||||
*/
|
||||
public FirstClassFunction(ArrayList<String> args, Statement st) {
|
||||
super(args.size());
|
||||
this.args = args;
|
||||
this.st = st;
|
||||
}
|
||||
@ -32,30 +37,16 @@ public class FirstClassFunction {
|
||||
* @return the result
|
||||
* @throws EvalException EvalException
|
||||
*/
|
||||
public Object evaluate(Object... args) throws EvalException {
|
||||
if (args.length != this.args.size())
|
||||
throw new EvalException("wrong number of arguments! found: " + args.length + ", expected: " + this.args.size());
|
||||
|
||||
@Override
|
||||
public Object f(Object... args) throws EvalException {
|
||||
Context c = new Context();
|
||||
for (int i = 0; i < args.length; i++)
|
||||
c.setVar(this.args.get(i), args[i]);
|
||||
st.execute(c);
|
||||
return c.getVar("return");
|
||||
if (c.contains("return"))
|
||||
return c.getVar("return");
|
||||
else
|
||||
throw new EvalException("A function must define the variable 'return'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a first class function
|
||||
*
|
||||
* @param context the context
|
||||
* @param args the arguments
|
||||
* @return the result
|
||||
* @throws EvalException EvalException
|
||||
*/
|
||||
public Object calcValue(Context context, ArrayList<Expression> args) throws EvalException {
|
||||
Object[] data = new Object[args.size()];
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
data[i] = args.get(i).value(context);
|
||||
|
||||
return evaluate(data);
|
||||
}
|
||||
}
|
46
src/main/java/de/neemann/digital/hdl/hgs/function/Func.java
Normal file
46
src/main/java/de/neemann/digital/hdl/hgs/function/Func.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.EvalException;
|
||||
|
||||
/**
|
||||
* A function.
|
||||
* Can be used to define a function by a lambda expression.
|
||||
*/
|
||||
public class Func extends FuncAdapter {
|
||||
private final Interface func;
|
||||
|
||||
/**
|
||||
* Creates a new function
|
||||
*
|
||||
* @param argCount the number of arguments
|
||||
* @param func the function
|
||||
*/
|
||||
public Func(int argCount, Interface func) {
|
||||
super(argCount);
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object f(Object... args) throws EvalException {
|
||||
return func.f(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* A fimple function
|
||||
*/
|
||||
public interface Interface {
|
||||
/**
|
||||
* Evaluates the function
|
||||
*
|
||||
* @param args the arguments
|
||||
* @return the result
|
||||
* @throws EvalException EvalException
|
||||
*/
|
||||
Object f(Object... args) throws EvalException;
|
||||
}
|
||||
}
|
@ -12,26 +12,35 @@ import de.neemann.digital.hdl.hgs.Expression;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Simple function adapter to implement a function with one argument of type long
|
||||
* 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() {
|
||||
super(1);
|
||||
public FuncAdapter(int argCount) {
|
||||
super(argCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) throws EvalException {
|
||||
return f(Expression.toLong(args.get(0).value(c)));
|
||||
if (getArgCount() != args.size())
|
||||
throw new EvalException("wrong number of arguments! found: " + args.size() + ", expected: " + args.size());
|
||||
|
||||
Object[] data = new Object[args.size()];
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
data[i] = args.get(i).value(c);
|
||||
return f(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function
|
||||
*
|
||||
* @param n the argument
|
||||
* @param args the evaluated arguments
|
||||
* @return the result
|
||||
* @throws EvalException EvalException
|
||||
*/
|
||||
protected abstract Object f(long n);
|
||||
protected abstract Object f(Object... args) throws EvalException;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple parser to parse text templates.
|
||||
* Classes to parse HG Script (HDL Generator Scripting language).
|
||||
* The user should not see any error messages from this template engine.
|
||||
* Therefore a translation of error messages is not necessary!
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@ import de.neemann.digital.hdl.hgs.Context;
|
||||
import de.neemann.digital.hdl.hgs.EvalException;
|
||||
|
||||
/**
|
||||
* A reference to a variable
|
||||
* A reference to a value
|
||||
*/
|
||||
public interface Reference {
|
||||
/**
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.refs;
|
||||
|
||||
import de.neemann.digital.hdl.hgs.Context;
|
||||
import de.neemann.digital.hdl.hgs.EvalException;
|
||||
import de.neemann.digital.hdl.hgs.Expression;
|
||||
import de.neemann.digital.hdl.hgs.function.Function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A reference to a function
|
||||
*/
|
||||
public class ReferenceToFunc implements Reference {
|
||||
private final Reference parent;
|
||||
private final ArrayList<Expression> args;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param parent the parent reference
|
||||
* @param args the arguments of the function
|
||||
*/
|
||||
public ReferenceToFunc(Reference parent, ArrayList<Expression> args) {
|
||||
this.parent = parent;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Context context, Object value) throws EvalException {
|
||||
throw new EvalException("set to function is not possible");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Context context) throws EvalException {
|
||||
Object funcObj = parent.get(context);
|
||||
if (funcObj instanceof Function)
|
||||
return ((Function) funcObj).calcValue(context, args);
|
||||
throw new EvalException("value is not a function");
|
||||
}
|
||||
}
|
@ -54,5 +54,4 @@ public class ReferenceToStruct implements Reference {
|
||||
throw new EvalException("not a map: " + m);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -32,11 +32,4 @@ public class ReferenceToVar implements Reference {
|
||||
public Object get(Context context) throws EvalException {
|
||||
return context.getVar(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the variable
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package de.neemann.digital.hdl.vhdl.lib;
|
||||
import de.neemann.digital.core.element.Key;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import 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.hdl.model.HDLException;
|
||||
@ -49,17 +50,20 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
if (inputStream == null)
|
||||
throw new IOException("file not present: " + createFileName(entityName));
|
||||
try (Reader in = new InputStreamReader(inputStream, "utf-8")) {
|
||||
Parser p = new Parser(in)
|
||||
.addFunction("type", new FunctionType())
|
||||
.addFunction("value", new FunctionValue())
|
||||
.addFunction("beginGenericPort", new Function(0) {
|
||||
Parser p = new Parser(in);
|
||||
statements = p.parse();
|
||||
staticContext = p.getStaticContext();
|
||||
staticContext
|
||||
.setVar("type", new FunctionType())
|
||||
.setVar("value", new FunctionValue())
|
||||
.setVar("beginGenericPort", new Function(0) {
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) throws EvalException {
|
||||
c.setVar("portStartPos", c.length());
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.addFunction("endGenericPort", new Function(0) {
|
||||
.setVar("endGenericPort", new Function(0) {
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) throws EvalException {
|
||||
int start = Expression.toInt(c.getVar("portStartPos"));
|
||||
@ -68,7 +72,7 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.addFunction("registerGeneric", new Function(1) {
|
||||
.setVar("registerGeneric", new Function(1) {
|
||||
@Override
|
||||
public Object calcValue(Context c, ArrayList<Expression> args) throws EvalException {
|
||||
List<String> generics;
|
||||
@ -83,8 +87,7 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
statements = p.parse();
|
||||
staticContext = p.getStaticContext();
|
||||
|
||||
} catch (ParserException e) {
|
||||
throw new IOException("error parsing template", e);
|
||||
}
|
||||
@ -180,7 +183,7 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
if (staticContext.contains("entityName")) {
|
||||
Object funcObj = staticContext.getVar("entityName");
|
||||
if (funcObj instanceof FirstClassFunction)
|
||||
name = ((FirstClassFunction) funcObj).evaluate(node.getAttributes()).toString();
|
||||
name = ((FirstClassFunction) funcObj).f(node.getAttributes()).toString();
|
||||
else
|
||||
name = funcObj.toString();
|
||||
}
|
||||
@ -208,7 +211,7 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
|
||||
private Entity(HDLNode node, String name) throws EvalException {
|
||||
this.name = name;
|
||||
final Context c = new Context(staticContext, new StringBuilder())
|
||||
final Context c = new Context(staticContext)
|
||||
.setVar("elem", node.getAttributes());
|
||||
statements.execute(c);
|
||||
code = c.toString();
|
||||
@ -248,13 +251,20 @@ public class VHDLTemplate implements VHDLEntity {
|
||||
}
|
||||
|
||||
private final static class FunctionType extends FuncAdapter {
|
||||
|
||||
private FunctionType() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object f(long n) {
|
||||
protected Object f(Object... args) throws EvalException {
|
||||
int n = Expression.toInt(args[0]);
|
||||
if (n == 1)
|
||||
return "std_logic";
|
||||
else
|
||||
return "std_logic_vector (" + (n - 1) + " downto 0)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class FunctionValue extends Function {
|
||||
|
@ -7,11 +7,17 @@ package de.neemann.digital.hdl.hgs;
|
||||
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -222,40 +228,40 @@ public class ParserTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testAddFunction() throws IOException, ParserException, EvalException {
|
||||
Statement s = new Parser("a : in <?=type(elem.Bits)?>;")
|
||||
.addFunction("type", new FuncAdapter() {
|
||||
@Override
|
||||
protected Object f(long n) {
|
||||
if (n == 1)
|
||||
return "std_logic";
|
||||
else
|
||||
return "std_logic_vector(" + (n - 1) + " downto 0)";
|
||||
}
|
||||
})
|
||||
.parse();
|
||||
Statement s = new Parser("a : in <?=type(elem.Bits)?>;").parse();
|
||||
Context funcs = new Context().setVar("type", new FuncAdapter(1) {
|
||||
@Override
|
||||
protected Object f(Object... args) throws EvalException {
|
||||
int n = Expression.toInt(args[0]);
|
||||
if (n == 1)
|
||||
return "std_logic";
|
||||
else
|
||||
return "std_logic_vector(" + (n - 1) + " downto 0)";
|
||||
}
|
||||
});
|
||||
assertEquals("a : in std_logic;",
|
||||
exec(s, new Context()
|
||||
exec(s, new Context(funcs)
|
||||
.setVar("elem", new ElementAttributes())).toString());
|
||||
assertEquals("a : in std_logic_vector(5 downto 0);",
|
||||
exec(s, new Context()
|
||||
exec(s, new Context(funcs)
|
||||
.setVar("elem", new ElementAttributes().setBits(6))).toString());
|
||||
}
|
||||
|
||||
long flag = 0;
|
||||
int flag = 0;
|
||||
|
||||
public void testFunctionAsStatement() throws IOException, ParserException, EvalException {
|
||||
flag = 0;
|
||||
Statement s = new Parser("a : in <? type(7); ?>;")
|
||||
.addFunction("type", new FuncAdapter() {
|
||||
@Override
|
||||
protected Object f(long n) {
|
||||
flag = n;
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.parse();
|
||||
assertEquals("a : in ;", exec(s).toString());
|
||||
assertEquals(7L, flag);
|
||||
Statement s = new Parser("a : in <? type(7); ?>;").parse();
|
||||
|
||||
Context c = new Context().setVar("type", new FuncAdapter(1) {
|
||||
@Override
|
||||
protected Object f(Object... args) throws EvalException {
|
||||
flag = Expression.toInt(args[0]);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
assertEquals("a : in ;", exec(s, c).toString());
|
||||
assertEquals(7, flag);
|
||||
}
|
||||
|
||||
public void testStatic() throws IOException, ParserException {
|
||||
@ -274,7 +280,7 @@ public class ParserTest extends TestCase {
|
||||
Object fObj = p.getStaticContext().getVar("f");
|
||||
assertTrue(fObj instanceof FirstClassFunction);
|
||||
FirstClassFunction f = (FirstClassFunction) fObj;
|
||||
assertEquals(11L, f.evaluate(3));
|
||||
assertEquals(11L, f.f(3));
|
||||
}
|
||||
|
||||
public void testFirstClassFunction() throws IOException, ParserException, EvalException {
|
||||
@ -282,6 +288,9 @@ public class ParserTest extends TestCase {
|
||||
assertEquals("5", exec("<? f=func(a,b){return=a+2*b;}; print(f(1,2));?>").toString());
|
||||
assertEquals("13", exec("<? f=func(a,b){return=a+2*b;}; print(f(1,a*2));?>",
|
||||
new Context().setVar("a", 3)).toString());
|
||||
|
||||
assertEquals("18", exec("<? m=newMap(); m.f=func(a){return=newMap(); return.v=a*a+2;}; print(m.f(4).v);?>").toString());
|
||||
|
||||
}
|
||||
|
||||
public void testFirstClassFunctionOutput() throws IOException, ParserException, EvalException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user