Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Add benchmark and speedup #37

Merged
merged 18 commits into from
Feb 1, 2024
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ module.exports = {
rules: {
// These off-by-default rules work well for this repo and we like them on.
"@typescript-eslint/no-confusing-void-expression": "off",
// "@typescript-eslint/switch-exhaustiveness-check": "error",
"deprecation/deprecation": "error",
"prefer-const": "off",
},
Expand Down
1 change: 1 addition & 0 deletions baselines/chapter12/attach-func-to-class.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
called function with argument
1 change: 1 addition & 0 deletions baselines/chapter12/call-detached-method.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Jane
1 change: 1 addition & 0 deletions baselines/chapter12/crunch-bacon.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Crunch crunch crunch!
1 change: 1 addition & 0 deletions baselines/chapter12/egotist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Egotist instance
2 changes: 2 additions & 0 deletions baselines/chapter12/failed-method-lookup.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Undefined property meth.
[line 3]
2 changes: 2 additions & 0 deletions baselines/chapter12/failed-property-lookup.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Undefined property prop.
[line 3]
2 changes: 2 additions & 0 deletions baselines/chapter12/get-non-instance.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Only instances have properties.
[line 2]
3 changes: 3 additions & 0 deletions baselines/chapter12/invoke-init-directly.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Foo instance
Foo instance
Foo instance
2 changes: 2 additions & 0 deletions baselines/chapter12/linked-list.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cons instance
3
1 change: 1 addition & 0 deletions baselines/chapter12/pathological-detachment.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Jane
2 changes: 2 additions & 0 deletions baselines/chapter12/print-instance.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Bagel instance
Bagel
1 change: 1 addition & 0 deletions baselines/chapter12/print-this-callback.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Thing instance
1 change: 1 addition & 0 deletions baselines/chapter12/return-value-from-init.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[line 3] Error at 'return': Can't return a value from an initializer.
2 changes: 2 additions & 0 deletions baselines/chapter12/set-non-instance.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Only instances have fields.
[line 2]
1 change: 1 addition & 0 deletions baselines/chapter12/tasty-cake.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The German chocolate cake is delicious!
1 change: 1 addition & 0 deletions baselines/chapter12/this-in-function.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[line 1] Error at 'this': Can't use 'this' outside of a class.
1 change: 1 addition & 0 deletions baselines/chapter12/this-outside-method.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[line 1] Error at 'this': Can't use 'this' outside of a class.
9 changes: 9 additions & 0 deletions bench/fib.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fun fib(n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}

var before = clock();
print fib(40);
var after = clock();
print after - before;
10 changes: 10 additions & 0 deletions bench/fib33.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fun fib(n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}

var before = clock();
print fib(33);
var after = clock();
print "Time elapsed (ms):";
print after - before;
3 changes: 2 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"autofix",
"quickfix",
"Nystrom",
"unshadow"
"unshadow",
"klass"
]
}
9 changes: 9 additions & 0 deletions examples/chapter12/attach-func-to-class.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Box {}

fun notMethod(argument) {
print "called function with " + argument;
}

var box = Box();
box.function = notMethod;
box.function("argument"); // should print argument
11 changes: 11 additions & 0 deletions examples/chapter12/call-detached-method.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Person {
sayName() {
print this.name;
}
}

var jane = Person();
jane.name = "Jane";

var method = jane.sayName;
method(); // should say "Jane"
7 changes: 7 additions & 0 deletions examples/chapter12/crunch-bacon.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Bacon {
eat() {
print "Crunch crunch crunch!";
}
}

Bacon().eat(); // Prints "Crunch crunch crunch!".
8 changes: 8 additions & 0 deletions examples/chapter12/egotist.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Egotist {
speak() {
print this;
}
}

var method = Egotist().speak;
method();
3 changes: 3 additions & 0 deletions examples/chapter12/failed-method-lookup.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Empty {}
var e = Empty();
print e.meth();
3 changes: 3 additions & 0 deletions examples/chapter12/failed-property-lookup.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Empty {}
var e = Empty();
print e.prop;
2 changes: 2 additions & 0 deletions examples/chapter12/get-non-instance.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var x = 123;
print x.length;
8 changes: 8 additions & 0 deletions examples/chapter12/invoke-init-directly.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Foo {
init() {
print this;
}
}

var foo = Foo();
print foo.init();
17 changes: 17 additions & 0 deletions examples/chapter12/linked-list.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Cons {
init(head, tail) {
this.head = head;
this.tail = tail;
}

length() {
if (this.tail) {
return 1 + this.tail.length();
}
return 1;
}
}

var abc = Cons("a", Cons("b", Cons("c", nil)));
print abc;
print abc.length();
14 changes: 14 additions & 0 deletions examples/chapter12/pathological-detachment.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Person {
sayName() {
print this.name;
}
}

var jane = Person();
jane.name = "Jane";

var bill = Person();
bill.name = "Bill";

bill.sayName = jane.sayName;
bill.sayName(); // should say Jane
4 changes: 4 additions & 0 deletions examples/chapter12/print-instance.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Bagel {}
var bagel = Bagel();
print bagel; // Prints "Bagel instance".
print Bagel; // Prints "Bagel"
12 changes: 12 additions & 0 deletions examples/chapter12/print-this-callback.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Thing {
getCallback() {
fun localFunction() {
print this;
}

return localFunction;
}
}

var callback = Thing().getCallback();
callback();
5 changes: 5 additions & 0 deletions examples/chapter12/return-value-from-init.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Foo {
init() {
return "something else";
}
}
5 changes: 5 additions & 0 deletions examples/chapter12/return-void-from-init.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Foo {
init() {
return;
}
}
2 changes: 2 additions & 0 deletions examples/chapter12/set-non-instance.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var x = 123;
x.base = 16;
10 changes: 10 additions & 0 deletions examples/chapter12/tasty-cake.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Cake {
taste() {
var adjective = "delicious";
print "The " + this.flavor + " cake is " + adjective + "!";
}
}

var cake = Cake();
cake.flavor = "German chocolate";
cake.taste(); // Prints "The German chocolate cake is delicious!".
1 change: 1 addition & 0 deletions examples/chapter12/this-in-function.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print this;
1 change: 1 addition & 0 deletions examples/chapter12/this-outside-method.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print this;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"README.md"
],
"scripts": {
"benchmark": "pnpm --silent run repl bench/fib33.lox",
"build": "tsup",
"coverage": "pnpm test -- --coverage --no-watch",
"format": "prettier \"**/*\" --ignore-unknown",
Expand Down
4 changes: 4 additions & 0 deletions src/ast-printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ export const astPrinter: ExpressionVisitor<string> & StmtVisitor<string> = {
...block.statements.map((stmt) => visitStmt(stmt, astPrinter)),
),
call: (expr) => parenthesize(expr.callee, ...expr.args),
class: (stmt) => parenthesizeText("class", stmt.name.lexeme, "..."),
expr: (stmt) => visitExpr(stmt.expression, astPrinter),
func: (stmt) =>
parenthesizeText(
"func",
parenthesizeText(stmt.name.lexeme, ...stmt.params.map((p) => p.lexeme)),
visitStmt({ kind: "block", statements: stmt.body }, astPrinter),
),
get: (expr) => parenthesize("get", expr.object, expr.name.lexeme),
grouping: (expr) => parenthesize("group", expr.expr),
if: (stmt) =>
parenthesizeText(
Expand All @@ -35,6 +37,8 @@ export const astPrinter: ExpressionVisitor<string> & StmtVisitor<string> = {
logical: (expr) => parenthesize(expr.operator.lexeme, expr.left, expr.right),
print: (stmt) => parenthesize("print", stmt.expression),
return: (stmt) => parenthesize("return", ...(stmt.value ? [stmt.value] : [])),
set: (expr) => parenthesize("set", expr.object, expr.name.lexeme, expr.value),
this: () => parenthesize("this"),
unary: (expr) => parenthesize(expr.operator.lexeme, expr.right),
"var-expr": (expr) => String(expr.name.literal),
"var-stmt": (stmt) =>
Expand Down
31 changes: 30 additions & 1 deletion src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ export interface Call {
args: Expr[];
}

export interface Get {
kind: "get";
object: Expr;
name: Token;
}

export interface This {
kind: "this";
keyword: Token;
}

// Statements

export interface Assign {
Expand Down Expand Up @@ -99,17 +110,34 @@ export interface Return {
value: Expr | null;
}

export interface Class {
kind: "class";
name: Token;
methods: Func[];
}

export interface SetExpr {
kind: "set";
object: Expr;
name: Token;
value: Expr;
}

export type Expr =
| Assign
| Binary
| Call
| Get
| Grouping
| Literal
| Logical
| SetExpr
| This
| Unary
| VarExpr;
export type Stmt =
| Block
| Class
| Expression
| Func
| IfStmt
Expand All @@ -127,7 +155,8 @@ export type StmtVisitor<R> = {

export function visitExpr<R>(expr: Expr, visitor: ExpressionVisitor<R>): R {
// XXX Can you model this without the "as never" in TS?
// -> I think the answer is "yes if TS had dependent types"
// https://stackoverflow.com/q/77876338/388951
// https://github.com/microsoft/TypeScript/issues/30581
return visitor[expr.kind](expr as never);
}

Expand Down
Loading
Loading