Skip to content

Commit 2406b07

Browse files
committed
Update to KtLox v1.1.0
1 parent 958aad9 commit 2406b07

39 files changed

Lines changed: 678 additions & 68 deletions

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# KtLox
2+
Kotlin Treewalk Interpreter for Lox
3+
4+
## Introduction
5+
KtLox is an implementation of the programming language Lox in Kotlin. Currently it uses naive treewalk interpreter, and is not optimized for speed. The initial version of KtLox has only features already present in the original JLox/CLox, but subsequent versions will continue to add new features to make it a powerful language. This is an experiment on the design and implementation of language features.
6+
7+
The original version of Lox programming language can be found at Bob Nystrom's repository:
8+
9+
https://github.com/munificent/craftinginterpreters
10+
11+
## Features
12+
- Lexer, Parser and Treewalk Interpreter
13+
- Unary and Binary Expression/Operators
14+
- If and Else Statement
15+
- While and For Loop
16+
- Break Statement(challenge from the book)
17+
- Scope and Environment
18+
- Functions and Closures
19+
- Resolver and Semantic Analysis
20+
- Anonymous Functions(challenge from the book)
21+
- Classes and Objects
22+
- Methods and Property Getters
23+
- Inheritance and this/super keywords
24+
- Metaclasses(challenge from the book)
25+
- Traits(challenge from the book)
26+
27+
## Roadmap
28+
29+
### KtLox v1.1.0(current version)
30+
- Improved object model - Everything is an object, including nil, true, false, number, string, etc.
31+
- Framework for writing Native functions and classes.
32+
- root class Object which serves as superclass of every class.
33+
34+
### KtLox v1.2.0(next version)
35+
- Full Fledged Standard Library: Boolean, Number, String, Array, Dictionary, DateTime, etc.
36+
- Mechanism for efficiently loading standard library at interpreter startup.
37+
- (maybe) Split the Number class, which will distinguish between integers and floating numbers.
38+
39+
### KtLox v1.3.0
40+
- Syntactic Sugar for Array/Dictionary Literals.
41+
- Short closures/lambda expression.
42+
- (maybe) Null-safe operator (?.).
43+
44+
### KtLox v1.4.0
45+
- Immutable variable declaration with **val**.
46+
- Function/method parameters are immutable by default(unless var keyword is used).
47+
- (maybe) Allow properties/instance variables to be defined inside the class statements, instead of initializers.
48+
49+
### KtLox v1.5.0
50+
- Refinement of metaclass system to match smalltalk's metaobject protocol.
51+
- Improvement of trait system in KtLox.
52+
- Add some Metaclasses and traits to the standard library.
53+
54+
### KtLox v1.6.0
55+
- Introduction of Namespace for KtLox's module system.
56+
- Allow importing namespaces and aliasing of imported classes/functions.
57+
- Redesign the existing standard library with namespaces(KtLox.Standard package).
58+
59+
### KtLox v1.7.0
60+
- Exception handling: throw statement, try/catch/finally statement, etc.
61+
- Add class Exception as well as a few more exception subclasses to the standard library.
62+
- (maybe) Pattern Matching
63+
64+
### Ktlox v1.8.0
65+
- Operator Overloading: enable user defined classes to overload operators, these operators are treated as method calls.
66+
- Method interception when an undefined method call is invoked on an object/class, similar to Smalltalk's doesNotUnderstand: message.
67+
- (maybe) Semicolon inference that allows semicolons to be omitted when its obvious that the statement is finished at the end of the line.
68+
69+
### KtLox v1.9.0
70+
- Introduction of async and await keywords, which allows C#/JS style of concurrency.
71+
- Add class Promise(or Future) to the standard library, which represents an async task to be completed in future.
72+
- (maybe) Continuation and Context, similar to smalltalk style stack manipulation.
73+
74+
### KtLox v2.0.0
75+
- Optional static typing support for instance variables and function/method parameters.
76+
- (maybe) Type inference for immutable variables, as well as possible optimization for typed variables.
77+
- (maybe) Slot as refied variables, similar to Pharo Smalltalk and Self's implementation.

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = "com.mysidia"
9-
version = "1.0.0"
9+
version = "1.1.0"
1010

1111
repositories {
1212
mavenCentral()

src/main/kotlin/Ast.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ object Ast {
3434
val grammarStmts = listOf(
3535
"Block : List<Stmt> statements",
3636
"Break : Token token",
37-
"Class : Token name, Expr.Variable? superclass, List<Expr.Variable> traits, List<Stmt.Function> methods, List<Stmt.Function> classMethods",
37+
"Class : Token name, Expr.Variable superclass, List<Expr.Variable> traits, List<Stmt.Function> methods, List<Stmt.Function> classMethods",
3838
"Function : Token name, Expr.Function functionBody",
3939
"Expression : Expr expression",
4040
"If : Expr condition, Stmt thenBranch, Stmt? elseBranch",

src/main/kotlin/ast/Stmt.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ abstract class Stmt {
2626
override fun <R> accept(visitor: Visitor<R>) = visitor.visitBreakStmt(this)
2727
}
2828

29-
data class Class(val name: Token, val superclass: Expr.Variable?, val traits: List<Expr.Variable>, val methods: List<Stmt.Function>, val classMethods: List<Stmt.Function>) : Stmt(){
29+
data class Class(val name: Token, val superclass: Expr.Variable, val traits: List<Expr.Variable>, val methods: List<Function>, val classMethods: List<Function>) : Stmt(){
3030
override fun <R> accept(visitor: Visitor<R>) = visitor.visitClassStmt(this)
3131
}
3232

@@ -50,7 +50,7 @@ abstract class Stmt {
5050
override fun <R> accept(visitor: Visitor<R>) = visitor.visitReturnStmt(this)
5151
}
5252

53-
data class Trait(val name: Token, val traits: List<Expr.Variable>, val methods: List<Stmt.Function>) : Stmt(){
53+
data class Trait(val name: Token, val traits: List<Expr.Variable>, val methods: List<Function>) : Stmt(){
5454
override fun <R> accept(visitor: Visitor<R>) = visitor.visitTraitStmt(this)
5555
}
5656

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.mysidia.ktlox.common
2+
3+
import com.mysidia.ktlox.interpreter.Interpreter
4+
5+
object LoxBooleanClass : LoxNativeClass("Boolean", LoxObjectClass){
6+
7+
init{
8+
defineNativeMetaclass("Boolean class")
9+
defineNativeMethod("isBoolean", 0, this::isBooleanDef)
10+
}
11+
12+
private fun isBooleanDef(interpreter: Interpreter, arguments: List<Any?>?) = true
13+
}

src/main/kotlin/common/LoxCallable.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ import com.mysidia.ktlox.interpreter.Interpreter
44

55
interface LoxCallable {
66
val arity : Int
7+
val isGetter : Boolean
8+
9+
fun bind(instance: LoxObject) : LoxCallable = this
710
fun call(interpreter: Interpreter, arguments: List<Any?>?) : Any?
811
}

src/main/kotlin/common/LoxClass.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@ package com.mysidia.ktlox.common
22

33
import com.mysidia.ktlox.interpreter.Interpreter
44

5-
class LoxClass(val name: String,
6-
private val superclass: LoxClass?,
7-
private val methods: MutableMap<String, LoxFunction>,
8-
metaclass: LoxClass?) : LoxInstance(metaclass), LoxCallable{
5+
open class LoxClass(val name: String,
6+
val superclass: LoxClass?,
7+
val methods: MutableMap<String, LoxCallable>,
8+
metaclass: LoxClass?) : LoxObject(metaclass), LoxCallable{
99

1010
private val initializer by lazy { findMethod("init") }
1111
override val arity get() = initializer?.arity ?: 0
12+
override val isGetter = false
1213

1314
override fun call(interpreter: Interpreter, arguments: List<Any?>?): Any {
14-
val instance = LoxInstance(this)
15-
initializer?.let { it.bind(instance).call(interpreter, arguments) }
15+
val instance = LoxObject(this)
16+
initializer?.bind(instance)?.call(interpreter, arguments)
1617
return instance
1718
}
1819

19-
fun findMethod(name: String) : LoxFunction? {
20+
fun findMethod(name: String) : LoxCallable? {
2021
if(methods.containsKey(name)) return methods[name]
2122
return superclass?.findMethod(name)
2223
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.mysidia.ktlox.common
2+
3+
import com.mysidia.ktlox.interpreter.Interpreter
4+
5+
object LoxClassClass : LoxNativeClass("Class", LoxObjectClass, null) {
6+
7+
init{
8+
defineNativeMethod("getSuperclass", 0, this::getSuperclassDef)
9+
defineNativeMethod("isClass", 0, this::isClassDef)
10+
defineNativeMethod("toString", 0, this::toStringDef)
11+
}
12+
13+
private fun getSuperclassDef(interpreter: Interpreter, arguments: List<Any?>?) = (interpreter.thisInstance as LoxClass).superclass
14+
15+
private fun isClassDef(interpreter: Interpreter, arguments: List<Any?>?) = true
16+
17+
private fun toStringDef(interpreter: Interpreter, arguments: List<Any?>?) = interpreter.thisInstance.className
18+
}

src/main/kotlin/common/LoxFalse.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.mysidia.ktlox.common
2+
3+
object LoxFalse : LoxObject(LoxFalseClass)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.mysidia.ktlox.common
2+
3+
import com.mysidia.ktlox.interpreter.Interpreter
4+
import com.mysidia.ktlox.interpreter.RuntimeError
5+
6+
object LoxFalseClass : LoxNativeClass("False", LoxBooleanClass) {
7+
8+
init{
9+
defineNativeMetaclass("False class")
10+
defineNativeMethod("init", 0, this::initDef)
11+
defineNativeMethod("toString", 0, this::toStringDef)
12+
}
13+
14+
private fun initDef(interpreter: Interpreter, arguments: List<Any?>?) : Any?{
15+
throw RuntimeError(interpreter.tokenFalse, "Cannot create instance from class False")
16+
}
17+
18+
private fun toStringDef(interpreter: Interpreter, arguments: List<Any?>?) = "false"
19+
}

0 commit comments

Comments
 (0)