I followed https://craftinginterpreters.com/functions.html and function call is implemented.
The interpreter can interpret block like this:
fun deco(func) {
fun impl() {
print "start" + func;
func();
print "end" + func;
}
return impl;
}
fun hello(){print "hello";}
var h2 = deco(hello);
h2();
with the result:
start<fn hello>
hello
end<fn hello>
However, as I recalled Python
decorator pattern, which is more concise, I want to add @
as a syntax sugar.
So I did the following modifications (github commit)
--- a/src/main/java/com/craftinginterpreters/lox/Scanner.java
+++ b/src/main/java/com/craftinginterpreters/lox/Scanner.java
@@ -31,6 +31,7 @@ public class Scanner {
keywords.put("true", TRUE);
keywords.put("var", VAR);
keywords.put("while", WHILE);
+ keywords.put("@", DECO);
}
Scanner(String source) {
@@ -65,6 +66,7 @@ public class Scanner {
case '+' -> addToken(PLUS);
case ';' -> addToken(SEMICOLON);
case '*' -> addToken(STAR);
+ case '@' -> addToken(DECO);
case '!' -> addToken(match('=') ? BANG_EQUAL : BANG);
case '=' -> addToken(match('=') ? EQUAL_EQUAL : EQUAL);
case '<' -> addToken(match('=') ? LESS_EQUAL : LESS);
--- a/src/main/java/com/craftinginterpreters/lox/Parser.java
+++ b/src/main/java/com/craftinginterpreters/lox/Parser.java
@@ -25,6 +25,7 @@ public class Parser {
try {
if (match(FUN)) return function("function");
if (match(VAR)) return varDeclaration();
+ if (match(DECO)) return decoDecl();
return statement();
} catch (ParseError error) {
synchonize();
@@ -32,19 +33,32 @@ public class Parser {
}
}
+ private Stmt decoDecl() {
+ Token deco_method = consume(IDENTIFIER, "expect deco name");
+ consume(FUN, "expect function after decorator");
+ Stmt.Function e2 = function("function");
+ Expr e3 = new Expr.Call(
+ new Expr.Variable(deco_method),
+ null,
+ Arrays.asList(
+ new Expr.Variable(e2.name)
+ )
+ );
+ return new Stmt.Var(e2.name, e3);
+ }
+
However, I don't know how to put the previous function declarations.
So it only works like this:
fun deco(func) {
fun impl() {
print "start" + func;
func();
print "end" + func;
}
return impl;
}
fun hello(){print "hello";}
^--- If removed this line the interpreter cannot found variable `hello`
@deco
fun hello(){print "hello";}
hello();
I tried using Stmt.Block
but since it creates a new scope the function declaration is discarded after exited the scope.
Any Suggestions?