mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-18 09:24:42 -04:00
added lambdas and a return statement
This commit is contained in:
parent
c03e29a710
commit
05b19ddcfb
@ -19,6 +19,7 @@ public class Context {
|
|||||||
private final Context parent;
|
private final Context parent;
|
||||||
private final StringBuilder code;
|
private final StringBuilder code;
|
||||||
private HashMap<String, Object> map;
|
private HashMap<String, Object> map;
|
||||||
|
private boolean functionContext = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new context
|
* Creates a new context
|
||||||
@ -156,6 +157,45 @@ public class Context {
|
|||||||
return parent.length();
|
return parent.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags this context as context belonging to a function call.
|
||||||
|
* This allows to use the return statement.
|
||||||
|
*
|
||||||
|
* @return this for chained calls
|
||||||
|
*/
|
||||||
|
public Context isFunctionContext() {
|
||||||
|
functionContext = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns from a function call.
|
||||||
|
*
|
||||||
|
* @param returnValue the return value
|
||||||
|
* @throws HGSEvalException HGSEvalException
|
||||||
|
*/
|
||||||
|
public void returnFromFunc(Object returnValue) throws HGSEvalException {
|
||||||
|
if (!functionContext)
|
||||||
|
throw new HGSEvalException("The return statement is allowed only in a function!");
|
||||||
|
|
||||||
|
throw new ReturnException(returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function from this context
|
||||||
|
*
|
||||||
|
* @param funcName the functions name
|
||||||
|
* @return the function
|
||||||
|
* @throws HGSEvalException HGSEvalException
|
||||||
|
*/
|
||||||
|
public FuncAdapter getFunction(String funcName) throws HGSEvalException {
|
||||||
|
Object fObj = getVar(funcName);
|
||||||
|
if (fObj instanceof FuncAdapter)
|
||||||
|
return (FuncAdapter) fObj;
|
||||||
|
else
|
||||||
|
throw new HGSEvalException("Variable '" + funcName + "' is not a function");
|
||||||
|
}
|
||||||
|
|
||||||
private static final class FunctionPrint extends Function {
|
private static final class FunctionPrint extends Function {
|
||||||
|
|
||||||
private FunctionPrint() {
|
private FunctionPrint() {
|
||||||
@ -163,7 +203,7 @@ public class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
for (Expression arg : args)
|
for (Expression arg : args)
|
||||||
c.print(arg.value(c).toString());
|
c.print(arg.value(c).toString());
|
||||||
return null;
|
return null;
|
||||||
@ -177,7 +217,7 @@ public class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
c.print(format(c, args));
|
c.print(format(c, args));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -190,7 +230,7 @@ public class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
return format(c, args);
|
return format(c, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +253,7 @@ public class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) {
|
||||||
try {
|
try {
|
||||||
args.get(0).value(c);
|
args.get(0).value(c);
|
||||||
return true;
|
return true;
|
||||||
@ -233,4 +273,28 @@ public class Context {
|
|||||||
throw new HGSEvalException(args[0].toString());
|
throw new HGSEvalException(args[0].toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception used to return a value from a function
|
||||||
|
*/
|
||||||
|
public static final class ReturnException extends HGSEvalException {
|
||||||
|
private final Object returnValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param returnValue the return value
|
||||||
|
*/
|
||||||
|
ReturnException(Object returnValue) {
|
||||||
|
super("return");
|
||||||
|
this.returnValue = returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the return value
|
||||||
|
*/
|
||||||
|
public Object getReturnValue() {
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package de.neemann.digital.hdl.hgs;
|
|||||||
|
|
||||||
import de.neemann.digital.core.Bits;
|
import de.neemann.digital.core.Bits;
|
||||||
import de.neemann.digital.hdl.hgs.function.FirstClassFunction;
|
import de.neemann.digital.hdl.hgs.function.FirstClassFunction;
|
||||||
|
import de.neemann.digital.hdl.hgs.function.FirstClassFunctionCall;
|
||||||
import de.neemann.digital.hdl.hgs.refs.*;
|
import de.neemann.digital.hdl.hgs.refs.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -179,6 +180,10 @@ public class Parser {
|
|||||||
while (!nextIs(CLOSEDBRACE))
|
while (!nextIs(CLOSEDBRACE))
|
||||||
s.add(parseStatement());
|
s.add(parseStatement());
|
||||||
return s.optimize();
|
return s.optimize();
|
||||||
|
case RETURN:
|
||||||
|
Expression retExp = parseExpression();
|
||||||
|
expect(SEMICOLON);
|
||||||
|
return c -> c.returnFromFunc(retExp.value(c));
|
||||||
default:
|
default:
|
||||||
throw newUnexpectedToken(token);
|
throw newUnexpectedToken(token);
|
||||||
}
|
}
|
||||||
@ -413,7 +418,7 @@ public class Parser {
|
|||||||
return exp;
|
return exp;
|
||||||
case FUNC:
|
case FUNC:
|
||||||
FirstClassFunction func = parseFunction();
|
FirstClassFunction func = parseFunction();
|
||||||
return c -> func;
|
return c -> new FirstClassFunctionCall(func, c);
|
||||||
default:
|
default:
|
||||||
throw newUnexpectedToken(t);
|
throw newUnexpectedToken(t);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class Tokenizer {
|
|||||||
UNKNOWN, IDENT, AND, OR, XOR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL,
|
UNKNOWN, IDENT, AND, OR, XOR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL,
|
||||||
ADD, SUB, MUL, GREATER, LESS, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
|
ADD, SUB, MUL, GREATER, LESS, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
|
||||||
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, STATIC, FUNC, GREATEREQUAL, LESSEQUAL,
|
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, STATIC, FUNC, GREATEREQUAL, LESSEQUAL,
|
||||||
REPEAT, UNTIL
|
REPEAT, RETURN, UNTIL
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashMap<String, Token> statementMap = new HashMap<>();
|
private static HashMap<String, Token> statementMap = new HashMap<>();
|
||||||
@ -31,6 +31,7 @@ class Tokenizer {
|
|||||||
statementMap.put("func", Token.FUNC);
|
statementMap.put("func", Token.FUNC);
|
||||||
statementMap.put("repeat", Token.REPEAT);
|
statementMap.put("repeat", Token.REPEAT);
|
||||||
statementMap.put("until", Token.UNTIL);
|
statementMap.put("until", Token.UNTIL);
|
||||||
|
statementMap.put("return", Token.RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Reader in;
|
private final Reader in;
|
||||||
|
@ -5,48 +5,33 @@
|
|||||||
*/
|
*/
|
||||||
package de.neemann.digital.hdl.hgs.function;
|
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.Statement;
|
import de.neemann.digital.hdl.hgs.Statement;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callable first class function
|
* Description of a first class function.
|
||||||
*/
|
*/
|
||||||
public class FirstClassFunction extends FuncAdapter {
|
public class FirstClassFunction {
|
||||||
private final ArrayList<String> args;
|
private final ArrayList<String> args;
|
||||||
private final Statement st;
|
private final Statement statement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
* @param args the names of the arguments
|
* @param args the names of the arguments
|
||||||
* @param st the function body
|
* @param statement the function body
|
||||||
*/
|
*/
|
||||||
public FirstClassFunction(ArrayList<String> args, Statement st) {
|
public FirstClassFunction(ArrayList<String> args, Statement statement) {
|
||||||
super(args.size());
|
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.st = st;
|
this.statement = statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ArrayList<String> getArgs() {
|
||||||
* Evaluates this function
|
return args;
|
||||||
*
|
|
||||||
* @param args the arguments
|
|
||||||
* @return the result
|
|
||||||
* @throws HGSEvalException HGSEvalException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object f(Object... args) throws HGSEvalException {
|
|
||||||
Context c = new Context();
|
|
||||||
for (int i = 0; i < args.length; i++)
|
|
||||||
c.setVar(this.args.get(i), args[i]);
|
|
||||||
st.execute(c);
|
|
||||||
if (c.contains("return"))
|
|
||||||
return c.getVar("return");
|
|
||||||
else
|
|
||||||
throw new HGSEvalException("A function must define the variable 'return'!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Statement getStatement() {
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to a first class function
|
||||||
|
*/
|
||||||
|
public final class FirstClassFunctionCall extends FuncAdapter {
|
||||||
|
private final FirstClassFunction func;
|
||||||
|
private final Context capturedContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param func the function
|
||||||
|
* @param context the captured context
|
||||||
|
*/
|
||||||
|
public FirstClassFunctionCall(FirstClassFunction func, Context context) {
|
||||||
|
super(func.getArgs().size());
|
||||||
|
this.func = func;
|
||||||
|
this.capturedContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object f(Object... args) throws HGSEvalException {
|
||||||
|
Context c = new Context(capturedContext).isFunctionContext();
|
||||||
|
for (int i = 0; i < args.length; i++)
|
||||||
|
c.setVar(func.getArgs().get(i), args[i]);
|
||||||
|
try {
|
||||||
|
func.getStatement().execute(c);
|
||||||
|
return null;
|
||||||
|
} catch (Context.ReturnException e) {
|
||||||
|
return e.getReturnValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,10 +25,7 @@ public abstract class FuncAdapter extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
if (getArgCount() != args.size())
|
|
||||||
throw new HGSEvalException("wrong number of arguments! found: " + args.size() + ", expected: " + getArgCount());
|
|
||||||
|
|
||||||
Object[] data = new Object[args.size()];
|
Object[] data = new Object[args.size()];
|
||||||
for (int i = 0; i < args.size(); i++)
|
for (int i = 0; i < args.size(); i++)
|
||||||
data[i] = args.get(i).value(c);
|
data[i] = args.get(i).value(c);
|
||||||
@ -36,11 +33,25 @@ public abstract class FuncAdapter extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The function
|
* Evaluates this function.
|
||||||
*
|
*
|
||||||
* @param args the evaluated arguments
|
* @param args the arguments
|
||||||
* @return the result
|
* @return the result
|
||||||
* @throws HGSEvalException HGSEvalException
|
* @throws HGSEvalException HGSEvalException
|
||||||
*/
|
*/
|
||||||
protected abstract Object f(Object... args) throws 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,5 +42,5 @@ public abstract class Function {
|
|||||||
* @return the value
|
* @return the value
|
||||||
* @throws HGSEvalException HGSEvalException
|
* @throws HGSEvalException HGSEvalException
|
||||||
*/
|
*/
|
||||||
public abstract Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException;
|
public abstract Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException;
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,12 @@ public class ReferenceToFunc implements Reference {
|
|||||||
@Override
|
@Override
|
||||||
public Object get(Context context) throws HGSEvalException {
|
public Object get(Context context) throws HGSEvalException {
|
||||||
Object funcObj = parent.get(context);
|
Object funcObj = parent.get(context);
|
||||||
if (funcObj instanceof Function)
|
if (funcObj instanceof Function) {
|
||||||
return ((Function) funcObj).calcValue(context, args);
|
final Function func = (Function) 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);
|
||||||
|
}
|
||||||
throw new HGSEvalException("Value is not a function!");
|
throw new HGSEvalException("Value is not a function!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,14 @@ public class VHDLTemplate implements VHDLEntity {
|
|||||||
.addFunc("value", new FunctionValue())
|
.addFunc("value", new FunctionValue())
|
||||||
.addFunc("beginGenericPort", new Function(0) {
|
.addFunc("beginGenericPort", new Function(0) {
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
c.setVar("portStartPos", c.length());
|
c.setVar("portStartPos", c.length());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.addFunc("endGenericPort", new Function(0) {
|
.addFunc("endGenericPort", new Function(0) {
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
int start = Value.toInt(c.getVar("portStartPos"));
|
int start = Value.toInt(c.getVar("portStartPos"));
|
||||||
String portDecl = c.toString().substring(start);
|
String portDecl = c.toString().substring(start);
|
||||||
c.setVar("portDecl", portDecl);
|
c.setVar("portDecl", portDecl);
|
||||||
@ -52,7 +52,7 @@ public class VHDLTemplate implements VHDLEntity {
|
|||||||
})
|
})
|
||||||
.addFunc("registerGeneric", new Function(-1) {
|
.addFunc("registerGeneric", new Function(-1) {
|
||||||
@Override
|
@Override
|
||||||
public Object calcValue(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
public Object callWithExpressions(Context c, ArrayList<Expression> args) throws HGSEvalException {
|
||||||
List<Generic> generics;
|
List<Generic> generics;
|
||||||
if (c.contains("generics"))
|
if (c.contains("generics"))
|
||||||
generics = (List<Generic>) c.getVar("generics");
|
generics = (List<Generic>) c.getVar("generics");
|
||||||
|
@ -300,25 +300,25 @@ public class ParserTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testFirstClassFunctionStatic() throws IOException, ParserException, HGSEvalException {
|
public void testFirstClassFunctionStatic() throws IOException, ParserException, HGSEvalException {
|
||||||
Parser p = new Parser("<? @f=func(a){return=a*a+2;}; print(f(4));?>");
|
Parser p = new Parser("<? @f=func(a){return a*a+2;}; print(f(4));?>");
|
||||||
p.parse();
|
p.parse();
|
||||||
Object fObj = p.getStaticContext().getVar("f");
|
Object fObj = p.getStaticContext().getVar("f");
|
||||||
assertTrue(fObj instanceof FirstClassFunction);
|
assertTrue(fObj instanceof FuncAdapter);
|
||||||
FirstClassFunction f = (FirstClassFunction) fObj;
|
FuncAdapter f = (FuncAdapter) fObj;
|
||||||
assertEquals(11L, f.f(3));
|
assertEquals(11L, f.call(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFirstClassFunction() throws IOException, ParserException, HGSEvalException {
|
public void testFirstClassFunction() throws IOException, ParserException, HGSEvalException {
|
||||||
assertEquals("18", exec("<? f=func(a){return=a*a+2;}; print(f(4));?>").toString());
|
assertEquals("18", exec("<? f=func(a){return a*a+2;}; print(f(4));?>").toString());
|
||||||
assertEquals("5", exec("<? f=func(a,b){return=a+2*b;}; print(f(1,2));?>").toString());
|
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));?>",
|
assertEquals("13", exec("<? f=func(a,b){return a+2*b;}; print(f(1,a*2));?>",
|
||||||
new Context().setVar("a", 3)).toString());
|
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());
|
assertEquals("18", exec("<? m=newMap(); m.f=func(a){m=newMap(); m.v=a*a+2; return m;}; print(m.f(4).v);?>").toString());
|
||||||
assertEquals("18", exec("<? m=newList(); m[0]=func(a){ l=newList(); l[0]=a*a+2; return=l;}; print(m[0](4)[0]);?>").toString());
|
assertEquals("18", exec("<? m=newList(); m[0]=func(a){ l=newList(); l[0]=a*a+2; return l;}; print(m[0](4)[0]);?>").toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertEquals("18", exec("<? f=func(a){return=a;}; f(1)=5; ?>").toString());
|
assertEquals("18", exec("<? f=func(a){return a;}; f(1)=5; ?>").toString());
|
||||||
fail();
|
fail();
|
||||||
} catch (HGSEvalException e) {
|
} catch (HGSEvalException e) {
|
||||||
}
|
}
|
||||||
@ -326,9 +326,25 @@ public class ParserTest extends TestCase {
|
|||||||
|
|
||||||
public void testFirstClassFunctionOutput() throws IOException, ParserException, HGSEvalException {
|
public void testFirstClassFunctionOutput() throws IOException, ParserException, HGSEvalException {
|
||||||
assertEquals("testtext12testtext15",
|
assertEquals("testtext12testtext15",
|
||||||
exec("<? f=func(a){ ?>testtext<? print(a*3); return=output; }; print(f(4),f(5));?>").toString());
|
exec("<? f=func(a){ ?>testtext<? print(a*3); return output; }; print(f(4),f(5));?>").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFirstClassFunctionLambda() throws IOException, ParserException, HGSEvalException {
|
||||||
|
Context c = exec("<? outer=5; f=func(x) {return x+outer;}; ?>");
|
||||||
|
FuncAdapter f = c.getFunction("f");
|
||||||
|
assertEquals(6L,f.call(1));
|
||||||
|
assertEquals(7L,f.call(2));
|
||||||
|
|
||||||
|
c = exec("<? f=func(x){ return func(u){return u*x;};}; a=f(2); b=f(5); ?>");
|
||||||
|
FuncAdapter a = c.getFunction("a");
|
||||||
|
FuncAdapter b = c.getFunction("b");
|
||||||
|
assertEquals(4L,a.call(2));
|
||||||
|
assertEquals(6L,a.call(3));
|
||||||
|
assertEquals(10L,b.call(2));
|
||||||
|
assertEquals(15L,b.call(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testPanic() throws IOException, ParserException, HGSEvalException {
|
public void testPanic() throws IOException, ParserException, HGSEvalException {
|
||||||
Statement s = new Parser("<? if (i>1) panic(\"myError\"); ?>").parse();
|
Statement s = new Parser("<? if (i>1) panic(\"myError\"); ?>").parse();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user