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

Implement index access syntax for classes #114

Merged
merged 1 commit into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions playground/src/pages/docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,13 @@ const Docs: React.FC = () => (
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="#inheritance ">
Inheritance
<Link className="nav-link" to="#classes-inheritance">
Class Inheritance
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="#classes-index-access">
Class Field/Method Index Access
</Link>
</li>
</ul>
Expand Down Expand Up @@ -413,8 +418,8 @@ const Docs: React.FC = () => (
height="300px"
/>
<DocCard
title="Inheritance"
anchor="inheritance"
title="Class Inheritance"
anchor="classes-inheritance"
code={[
'class Greeter {',
' let greeting;',
Expand Down Expand Up @@ -442,6 +447,29 @@ const Docs: React.FC = () => (
height="400px"
/>

<DocCard
title="Class Field/Method Index Access"
anchor="classes-index-access"
code={[
'class Box {',
' let value;',
'',
' fn init(value) {',
' this["value"] = value;',
' }',
'',
' fn get() {',
' return this["value"];',
' }',
'}',
'',
'let box = Box(123);',
'',
'print box.get(); // out: 123',
]}
height="275px"
/>

<div className="shadow rounded p-3 vstack gap-3">
<h2 id="errors">
Errors{' '}
Expand Down
15 changes: 15 additions & 0 deletions res/examples/field/index_access_get_method_on_instance.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Box {
let value;

fn init(value) {
this.value = value;
}

fn get() {
return this.value;
}
}

let box = Box(123);

print box["get"](); // out: 123
23 changes: 23 additions & 0 deletions res/examples/field/index_access_get_nested.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Object {
let box;

fn init(value) {
this.box = Box(value);
}
}

class Box {
let value;

fn init(value) {
this.value = value;
}

fn get() {
return this.value;
}
}

let obj = Object(123);

print obj["box"]["get"](); // out: 123
25 changes: 25 additions & 0 deletions res/examples/field/index_access_get_set_on_super.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Parent {
let value;

fn init(value) {
this["value"] = value;
}

fn get() {
return this["value"];
}
}

class Child extends Parent {
fn init(value) {
super["init"](value);
}

fn get() {
return this.value;
}
}

let child = Child(123);

print child.get(); // out: 123
15 changes: 15 additions & 0 deletions res/examples/field/index_access_get_set_on_this.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Box {
let value;

fn init(value) {
this["value"] = value;
}

fn get() {
return this["value"];
}
}

let box = Box(123);

print box.get(); // out: 123
6 changes: 6 additions & 0 deletions res/examples/field/index_access_get_undefined.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Object {
}

let obj = Object();

print obj["key"]; // out: AttributeError: "Object" object has no attribute "key"
15 changes: 15 additions & 0 deletions res/examples/field/index_access_set_method_on_instance.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Box {
let value;

fn init(value) {
this.value = value;
}

fn get() {
return this.value;
}
}

let box = Box(123);

box["get"] = 123; // out: TypeError: methods on instances can not be reassigned (e.g. instance<Box>.get = "...")
6 changes: 6 additions & 0 deletions res/examples/field/index_access_set_undefined.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Object {
}

let obj = Object();

obj["key"] = "new value"; // out: AttributeError: "Object" object has no attribute "key"
12 changes: 12 additions & 0 deletions res/examples/field/index_access_with_expr.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Record {
let key = "value";
}

let key = "key";
let record = Record();

print record[key]; // out: value

record[key] = "new value";

print record[key]; // out: new value
11 changes: 11 additions & 0 deletions res/examples/field/index_access_with_string.locks
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Record {
let key = "value";
}

let record = Record();

print record["key"]; // out: value

record["key"] = "new value";

print record["key"]; // out: new value
26 changes: 26 additions & 0 deletions res/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ ExprAssign = {
})),
<object:Spanned<ExprCall>> "." <name:identifier> "=" <value:ExprS> =>
ast::Expr::Set(Box::new(ast::ExprSet { <> })),
<object:Spanned<ExprCall>> "[" <name:identifier> "]" "=" <value:ExprS> =>
ast::Expr::Set(Box::new(ast::ExprSet { <> })),
<object:Spanned<ExprCall>> "[" <name:string> "]" "=" <value:ExprS> =>
ast::Expr::Set(Box::new(ast::ExprSet { <> })),
ExprLogicOr,
}

Expand Down Expand Up @@ -172,6 +176,10 @@ ExprCall: ast::Expr = {
ast::Expr::Call(Box::new(ast::ExprCall { callee, args })),
<object:Spanned<ExprCall>> "." <name:identifier> =>
ast::Expr::Get(Box::new(ast::ExprGet { <> })),
<object:Spanned<ExprCall>> "[" <name:string> "]" =>
ast::Expr::Get(Box::new(ast::ExprGet { <> })),
<object:Spanned<ExprCall>> "[" <name:identifier> "]" =>
ast::Expr::Get(Box::new(ast::ExprGet { <> })),
"super" "." <name:identifier> =>
ast::Expr::Super(ast::ExprSuper {
super_: ast::Identifier {
Expand All @@ -180,6 +188,22 @@ ExprCall: ast::Expr = {
},
name,
}),
"super" "[" <name:string> "]" =>
ast::Expr::Super(ast::ExprSuper {
super_: ast::Identifier {
name: "super".to_string(),
depth: None,
},
name,
}),
"super" "[" <name:identifier> "]" =>
ast::Expr::Super(ast::ExprSuper {
super_: ast::Identifier {
name: "super".to_string(),
depth: None,
},
name,
}),
ExprPrimary,
}

Expand Down Expand Up @@ -253,6 +277,8 @@ extern {
")" => lexer::Token::RtParen,
"{" => lexer::Token::LtBrace,
"}" => lexer::Token::RtBrace,
"[" => lexer::Token::LtBracket,
"]" => lexer::Token::RtBracket,
"," => lexer::Token::Comma,
"." => lexer::Token::Dot,
"-" => lexer::Token::Minus,
Expand Down
4 changes: 4 additions & 0 deletions src/syntax/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ pub enum Token {
LtBrace,
#[token("}")]
RtBrace,
#[token("[")]
LtBracket,
#[token("]")]
RtBracket,
#[token(",")]
Comma,
#[token(".")]
Expand Down
4 changes: 0 additions & 4 deletions src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,10 +788,6 @@ impl VM {
/// Create a new [`ObjectInstance`] of an [`ObjectClass`].
///
/// Calls the `init` method if it exists on the [`ObjectClass`].
///
/// ```
/// let instance = Class();
/// ```
fn call_class(&mut self, class: *mut ObjectClass, arg_count: usize) -> Result<()> {
let instance = self.alloc(ObjectInstance::new(class));

Expand Down
Loading