mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-18 17:34:43 -04:00
added first class functions
This commit is contained in:
parent
11588d270f
commit
4d15ea268a
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callable first class function
|
||||||
|
*/
|
||||||
|
public class FirstClassFunction {
|
||||||
|
private final ArrayList<String> args;
|
||||||
|
private final Statement st;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param args the names of the arguments
|
||||||
|
* @param st the function body
|
||||||
|
*/
|
||||||
|
public FirstClassFunction(ArrayList<String> args, Statement st) {
|
||||||
|
this.args = args;
|
||||||
|
this.st = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates this function
|
||||||
|
*
|
||||||
|
* @param args the arguments
|
||||||
|
* @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());
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
@ -415,13 +415,13 @@ public class Parser {
|
|||||||
}
|
}
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
long num = convToLong(tok.getIdent());
|
long num = convToLong(tok.getIdent());
|
||||||
return (c) -> num;
|
return c -> num;
|
||||||
case STRING:
|
case STRING:
|
||||||
String s = tok.getIdent();
|
String s = tok.getIdent();
|
||||||
return (c) -> s;
|
return c -> s;
|
||||||
case SUB:
|
case SUB:
|
||||||
Expression negExp = parseIdent();
|
Expression negExp = parseIdent();
|
||||||
return (c) -> -Expression.toLong(negExp.value(c));
|
return c -> -Expression.toLong(negExp.value(c));
|
||||||
case NOT:
|
case NOT:
|
||||||
Expression notExp = parseIdent();
|
Expression notExp = parseIdent();
|
||||||
return (c) -> Expression.not(notExp.value(c));
|
return (c) -> Expression.not(notExp.value(c));
|
||||||
@ -429,19 +429,45 @@ public class Parser {
|
|||||||
Expression exp = parseExpression();
|
Expression exp = parseExpression();
|
||||||
expect(Tokenizer.Token.CLOSE);
|
expect(Tokenizer.Token.CLOSE);
|
||||||
return exp;
|
return exp;
|
||||||
|
case FUNC:
|
||||||
|
FirstClassFunction func = parseFunction();
|
||||||
|
return c -> func;
|
||||||
default:
|
default:
|
||||||
throw newUnexpectedToken(t);
|
throw newUnexpectedToken(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FirstClassFunction parseFunction() throws IOException, ParserException {
|
||||||
|
expect(OPEN);
|
||||||
|
ArrayList<String> args = new ArrayList<>();
|
||||||
|
if (!isToken(CLOSE)) {
|
||||||
|
expect(IDENT);
|
||||||
|
args.add(tok.getIdent());
|
||||||
|
while (!isToken(CLOSE)) {
|
||||||
|
expect(COMMA);
|
||||||
|
expect(IDENT);
|
||||||
|
args.add(tok.getIdent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement st = parseStatements();
|
||||||
|
return new FirstClassFunction(args, st);
|
||||||
|
}
|
||||||
|
|
||||||
private Expression findFunction(String name, ArrayList<Expression> args) throws ParserException {
|
private Expression findFunction(String name, ArrayList<Expression> args) throws ParserException {
|
||||||
Function f = functions.get(name);
|
Function f = functions.get(name);
|
||||||
if (f == null)
|
if (f != null) {
|
||||||
throw newParserException("function " + name + " not found");
|
|
||||||
if (f.getArgCount() != args.size() && f.getArgCount() >= 0)
|
if (f.getArgCount() != args.size() && f.getArgCount() >= 0)
|
||||||
throw newParserException("function " + name + " needs " + f.getArgCount() + "arguments, but found " + args.size());
|
throw newParserException("function " + name + " needs " + f.getArgCount() + "arguments, but found " + args.size());
|
||||||
|
return c -> f.calcValue(c, args);
|
||||||
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");
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ public class Tokenizer {
|
|||||||
enum Token {
|
enum Token {
|
||||||
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, SMALER, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
|
ADD, SUB, MUL, GREATER, SMALER, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
|
||||||
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, PRINT, STATIC, PRINTF
|
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, PRINT, STATIC, FUNC, PRINTF
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashMap<String, Token> statementMap = new HashMap<>();
|
private static HashMap<String, Token> statementMap = new HashMap<>();
|
||||||
@ -29,6 +29,7 @@ public class Tokenizer {
|
|||||||
statementMap.put("while", Token.FOR);
|
statementMap.put("while", Token.FOR);
|
||||||
statementMap.put("print", Token.PRINT);
|
statementMap.put("print", Token.PRINT);
|
||||||
statementMap.put("printf", Token.PRINTF);
|
statementMap.put("printf", Token.PRINTF);
|
||||||
|
statementMap.put("func", Token.FUNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Reader in;
|
private final Reader in;
|
||||||
|
@ -182,7 +182,7 @@ public class ParserTest extends TestCase {
|
|||||||
|
|
||||||
public void testParseTemplateMapError() throws IOException, ParserException {
|
public void testParseTemplateMapError() throws IOException, ParserException {
|
||||||
try {
|
try {
|
||||||
Context c = exec("<? m=1; m.test=2; ?>;");
|
exec("<? m=1; m.test=2; ?>;");
|
||||||
fail();
|
fail();
|
||||||
} catch (EvalException e) {
|
} catch (EvalException e) {
|
||||||
assertTrue(true);
|
assertTrue(true);
|
||||||
@ -191,7 +191,7 @@ public class ParserTest extends TestCase {
|
|||||||
|
|
||||||
public void testParseTemplateArrayError() throws IOException, ParserException {
|
public void testParseTemplateArrayError() throws IOException, ParserException {
|
||||||
try {
|
try {
|
||||||
Context c = exec("<? m=1; m[0]=2; ?>;");
|
exec("<? m=1; m[0]=2; ?>;");
|
||||||
fail();
|
fail();
|
||||||
} catch (EvalException e) {
|
} catch (EvalException e) {
|
||||||
assertTrue(true);
|
assertTrue(true);
|
||||||
@ -239,13 +239,29 @@ public class ParserTest extends TestCase {
|
|||||||
assertEquals("a", generics.get(0));
|
assertEquals("a", generics.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFirstClassFunctionStatic() throws IOException, ParserException, EvalException {
|
||||||
|
Parser p = new Parser("<? @f=func(a){return=a*a+2;}; print(f(4));?>");
|
||||||
|
p.parse();
|
||||||
|
Object fObj = p.getStaticContext().getVar("f");
|
||||||
|
assertTrue(fObj instanceof FirstClassFunction);
|
||||||
|
FirstClassFunction f = (FirstClassFunction) fObj;
|
||||||
|
assertEquals(11L, f.evaluate(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFirstClassFunction() throws IOException, ParserException, EvalException {
|
||||||
|
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("13", exec("<? f=func(a,b){return=a+2*b;}; print(f(1,a*2));?>",
|
||||||
|
new Context().setVar("a", 3)).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// public void testCode() throws IOException, ParserException {
|
// public void testCode() throws IOException, ParserException {
|
||||||
// File dir = new File("/home/hneemann/temp/Digital/ideras/Digital/src/main/resources/verilog");
|
// File dir = new File("/home/hneemann/temp/Digital/ideras/Digital/src/main/resources/verilog");
|
||||||
// for (File f : dir.listFiles()) {
|
// for (File f : dir.listFiles()) {
|
||||||
// try (Reader r = new FileReader(f)) {
|
// try (Reader r = new FileReader(f)) {
|
||||||
// System.out.println(f);
|
// System.out.println(f);
|
||||||
// new Template(r);
|
// new Parser(r).parse();
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user