Chapter 12, Sections 1, 2, and 3
This commit is contained in:
parent
b04b6bcf2f
commit
580a5acb58
7 changed files with 137 additions and 4 deletions
|
@ -23,4 +23,6 @@ add_jar(Lox
|
||||||
LoxFunction.java
|
LoxFunction.java
|
||||||
Return.java
|
Return.java
|
||||||
Resolver.java
|
Resolver.java
|
||||||
|
LoxClass.java
|
||||||
|
LoxInstance.java
|
||||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
||||||
|
|
|
@ -49,6 +49,19 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return evaluate(expr.right);
|
return evaluate(expr.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitSetExpr(Expr.Set expr) {
|
||||||
|
Object object = evaluate(expr.object);
|
||||||
|
|
||||||
|
if (!(object instanceof LoxInstance)) {
|
||||||
|
throw new RuntimeError(expr.name, "Only instances have fields.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = evaluate(expr.value);
|
||||||
|
((LoxInstance) object).set(expr.name, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitUnaryExpr(Expr.Unary expr) {
|
public Object visitUnaryExpr(Expr.Unary expr) {
|
||||||
Object right = evaluate(expr.right);
|
Object right = evaluate(expr.right);
|
||||||
|
@ -161,6 +174,14 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitClassStmt(Stmt.Class stmt) {
|
||||||
|
environment.define(stmt.name.lexeme, null);
|
||||||
|
LoxClass klass = new LoxClass(stmt.name.lexeme);
|
||||||
|
environment.assign(stmt.name, klass);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitExpressionStmt(Stmt.Expression stmt) {
|
public Void visitExpressionStmt(Stmt.Expression stmt) {
|
||||||
evaluate(stmt.expression);
|
evaluate(stmt.expression);
|
||||||
|
@ -304,6 +325,16 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return function.call(this, arguments);
|
return function.call(this, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitGetExpr(Expr.Get expr) {
|
||||||
|
Object object = evaluate(expr.object);
|
||||||
|
if (object instanceof LoxInstance) {
|
||||||
|
return ((LoxInstance) object).get(expr.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeError(expr.name, "Only instances have properties.");
|
||||||
|
}
|
||||||
|
|
||||||
public void interpret(List<Stmt> statements) {
|
public void interpret(List<Stmt> statements) {
|
||||||
try {
|
try {
|
||||||
for (Stmt statement : statements) {
|
for (Stmt statement : statements) {
|
||||||
|
|
27
src/com/craftinginterpreters/lox/LoxClass.java
Normal file
27
src/com/craftinginterpreters/lox/LoxClass.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package com.craftinginterpreters.lox;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class LoxClass implements LoxCallable {
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
LoxClass(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object call(Interpreter interpreter, List<Object> arguments) {
|
||||||
|
LoxInstance instance = new LoxInstance(this);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int arity() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
30
src/com/craftinginterpreters/lox/LoxInstance.java
Normal file
30
src/com/craftinginterpreters/lox/LoxInstance.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package com.craftinginterpreters.lox;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class LoxInstance {
|
||||||
|
private LoxClass klass;
|
||||||
|
private final Map<String, Object> fields = new HashMap<>();
|
||||||
|
|
||||||
|
LoxInstance(LoxClass klass) {
|
||||||
|
this.klass = klass;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object get(Token name) {
|
||||||
|
if (fields.containsKey(name.lexeme)) {
|
||||||
|
return fields.get(name.lexeme);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeError(name, "Undefined proprety '" + name.lexeme + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(Token name, Object value) {
|
||||||
|
fields.put(name.lexeme, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return klass.name + " instance";
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,8 @@ class Parser {
|
||||||
|
|
||||||
private Stmt declaration() {
|
private Stmt declaration() {
|
||||||
try {
|
try {
|
||||||
|
if (match(CLASS))
|
||||||
|
return classDeclaration();
|
||||||
if (match(FUN))
|
if (match(FUN))
|
||||||
return function("function");
|
return function("function");
|
||||||
if (match(VAR))
|
if (match(VAR))
|
||||||
|
@ -45,6 +47,20 @@ class Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stmt classDeclaration() {
|
||||||
|
Token name = consume(IDENTIFIER, "Expect class name.");
|
||||||
|
consume(LEFT_BRACE, "Expect '{' before class body.");
|
||||||
|
|
||||||
|
List<Stmt.Function> methods = new ArrayList<>();
|
||||||
|
while (!check(RIGHT_BRACE) && !isAtEnd()) {
|
||||||
|
methods.add(function("method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
consume(RIGHT_BRACE, "Expect '}' after class body.");
|
||||||
|
|
||||||
|
return new Stmt.Class(name, methods);
|
||||||
|
}
|
||||||
|
|
||||||
private Stmt statement() {
|
private Stmt statement() {
|
||||||
if (match(FOR))
|
if (match(FOR))
|
||||||
return forStatement();
|
return forStatement();
|
||||||
|
@ -201,6 +217,9 @@ class Parser {
|
||||||
if (expr instanceof Expr.Variable) {
|
if (expr instanceof Expr.Variable) {
|
||||||
Token name = ((Expr.Variable) expr).name;
|
Token name = ((Expr.Variable) expr).name;
|
||||||
return new Expr.Assign(name, value);
|
return new Expr.Assign(name, value);
|
||||||
|
} else if (expr instanceof Expr.Get) {
|
||||||
|
Expr.Get get = (Expr.Get)expr;
|
||||||
|
return new Expr.Set(get.object, get.name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(equals, "Invalid assignment target.");
|
error(equals, "Invalid assignment target.");
|
||||||
|
@ -313,6 +332,9 @@ class Parser {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (match(LEFT_PAREN)) {
|
if (match(LEFT_PAREN)) {
|
||||||
expr = finishCall(expr);
|
expr = finishCall(expr);
|
||||||
|
} else if (match(DOT)) {
|
||||||
|
Token name = consume(IDENTIFIER, "Expect property name after '.'");
|
||||||
|
expr = new Expr.Get(expr, name);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,13 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitClassStmt(Stmt.Class stmt) {
|
||||||
|
declare(stmt.name);
|
||||||
|
define(stmt.name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitExpressionStmt(Stmt.Expression stmt) {
|
public Void visitExpressionStmt(Stmt.Expression stmt) {
|
||||||
resolve(stmt.expression);
|
resolve(stmt.expression);
|
||||||
|
@ -117,6 +124,12 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitGetExpr(Expr.Get expr) {
|
||||||
|
resolve(expr.object);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitGroupingExpr(Expr.Grouping expr) {
|
public Void visitGroupingExpr(Expr.Grouping expr) {
|
||||||
resolve(expr.expression);
|
resolve(expr.expression);
|
||||||
|
@ -128,6 +141,13 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitSetExpr(Expr.Set expr) {
|
||||||
|
resolve(expr.value);
|
||||||
|
resolve(expr.object);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitLogicalExpr(Expr.Logical expr) {
|
public Void visitLogicalExpr(Expr.Logical expr) {
|
||||||
resolve(expr.left);
|
resolve(expr.left);
|
||||||
|
|
|
@ -16,12 +16,13 @@ public class GenerateAst {
|
||||||
|
|
||||||
defineAst(outputDir, "Expr",
|
defineAst(outputDir, "Expr",
|
||||||
Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right",
|
Arrays.asList("Assign : Token name, Expr value", "Binary : Expr left, Token operator, Expr right",
|
||||||
"Call : Expr callee, Token paren, List<Expr> arguments", "Grouping : Expr expression",
|
"Call : Expr callee, Token paren, List<Expr> arguments", "Get : Expr object, Token name",
|
||||||
"Literal : Object value", "Logical : Expr left, Token operator, Expr right",
|
"Grouping : Expr expression", "Literal : Object value",
|
||||||
|
"Logical : Expr left, Token operator, Expr right", "Set : Expr object, Token name, Expr value",
|
||||||
"Unary : Token operator, Expr right", "Variable : Token name"));
|
"Unary : Token operator, Expr right", "Variable : Token name"));
|
||||||
defineAst(outputDir, "Stmt",
|
defineAst(outputDir, "Stmt",
|
||||||
Arrays.asList("Block : List<Stmt> statements", "Expression : Expr expression",
|
Arrays.asList("Block : List<Stmt> statements", "Class : Token name, List<Stmt.Function> methods",
|
||||||
"Function : Token name, List<Token> params, List<Stmt> body",
|
"Expression : Expr expression", "Function : Token name, List<Token> params, List<Stmt> body",
|
||||||
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
|
||||||
"Return : Token keyword, Expr value", "Var : Token name, Expr initializer",
|
"Return : Token keyword, Expr value", "Var : Token name, Expr initializer",
|
||||||
"While : Expr condition, Stmt body"));
|
"While : Expr condition, Stmt body"));
|
||||||
|
|
Loading…
Reference in a new issue