Skip to content

Commit 81ce271

Browse files
committed
oop classes start ik value::instance no existy
1 parent c7ca04e commit 81ce271

7 files changed

Lines changed: 127 additions & 3 deletions

File tree

lang/examples/oop.modu

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Counter {
2+
fn new(start) {
3+
self.value = start;
4+
}
5+
6+
fn increment() {
7+
self.value += 1;
8+
}
9+
10+
fn decrement() {
11+
self.value -= 1;
12+
}
13+
14+
fn value() {
15+
return self.value;
16+
}
17+
18+
fn reset() {
19+
self.value = 0;
20+
}
21+
}
22+
23+
let counter = Counter(1);
24+
counter.increment();
25+
26+
print(counter.value);
27+
28+
counter.decrement();
29+
print(counter.value());
30+
31+
counter.reset();
32+
counter.decrement();
33+
print(counter.value);

lang/src/ast.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,10 @@ pub enum Expr {
121121
NotIn(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
122122
And(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
123123
Or(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
124-
Not(Box<Spanned<Expr>>)
124+
Not(Box<Spanned<Expr>>),
125+
126+
Class {
127+
name: String,
128+
methods: Vec<Spanned<Expr>>,
129+
}
125130
}

lang/src/compiler/compiler.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use chumsky::span::SimpleSpan;
2+
use std::collections::HashMap;
23

34
use crate::vm::chunk::Chunk;
45
use crate::vm::instruction::Instruction;
@@ -559,6 +560,54 @@ impl Compiler {
559560
Expr::Import { name, alias } => {
560561
self.emit(Instruction::Import { path: name.clone(), alias: alias.clone() }, span);
561562
}
563+
564+
Expr::Class { name, methods } => {
565+
let mut methods_map = HashMap::new();
566+
567+
for f in methods {
568+
if let Expr::Function { name: method_name, args, body } = &f.node {
569+
let chunk_id = self.chunks.len() + self.offset;
570+
self.chunks.push(Chunk::new(&format!("{}::{}", name, method_name)));
571+
572+
let saved_chunk = self.current_chunk;
573+
self.current_chunk = chunk_id;
574+
575+
let saved_scope = self.scope.enter_function();
576+
self.scope.define_local("self");
577+
578+
for arg in args {
579+
self.scope.define_local(arg);
580+
}
581+
582+
self.compile_expr(*body.clone())?;
583+
584+
if method_name == "new" {
585+
self.emit(Instruction::LoadLocal(0), span);
586+
} else {
587+
self.emit(Instruction::PushNull, span);
588+
}
589+
590+
self.emit(Instruction::Return, span);
591+
592+
let locals_count = self.scope.exit_function(saved_scope);
593+
self.chunks[chunk_id].locals_count = locals_count;
594+
self.current_chunk = saved_chunk;
595+
596+
methods_map.insert(
597+
method_name.clone(),
598+
Value::Function { chunk_id, arity: args.len() }
599+
);
600+
} else {
601+
return Err("class body can only contain functions".to_string());
602+
}
603+
}
604+
605+
let class_value = Value::Class { name: name.clone(), methods: methods_map };
606+
let index = self.add_constant(class_value);
607+
608+
self.emit(Instruction::Push(index), span);
609+
self.store_variable(name, span);
610+
}
562611
}
563612

564613
Ok(())

lang/src/lexer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ pub enum Token {
9292
#[token("fn")]
9393
Function,
9494

95+
#[token("class")]
96+
Class,
97+
9598
#[token("import")]
9699
Import,
97100

lang/src/parser.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ fn parser<'src>() -> impl Parser<
118118
},
119119

120120
Postfix::Call(args) => SpannedExpr {
121-
span: (obj.span.start..(obj.span.end + 2)).into(), // include ()
121+
span: (obj.span.start..(
122+
obj.span.end + 2
123+
+ args.iter().map(|arg| arg.span.end - arg.span.start).sum::<usize>()
124+
+ (args.len().saturating_sub(1) * 2))
125+
).into(), // so it marks (..) in call(..)
122126
node: Expr::Call {
123127
callee: Box::new(obj.clone()),
124128
args,
@@ -370,6 +374,19 @@ fn parser<'src>() -> impl Parser<
370374
})
371375
.labelled("function declaration");
372376

377+
let class_stmt = select! { (Token::Class, span) => span }
378+
.then(select! { (Token::Identifier(name), _) => name }.labelled("class name"))
379+
.then(
380+
select! { (Token::LBrace, span) => span }
381+
.then(fn_stmt.clone().repeated().collect::<Vec<_>>())
382+
.then(select! { (Token::RBrace, span) => span })
383+
)
384+
.map(|((start, name), ((_lbrace, methods), end)): ((Span, String), ((Span, Vec<SpannedExpr>), Span))| SpannedExpr {
385+
node: Expr::Class { name, methods },
386+
span: Span::from(start.start..end.end),
387+
})
388+
.labelled("class declaration");
389+
373390
let infinite_loop_stmt = select! { (Token::Loop, span) => span }
374391
.then(block.clone().labelled("loop body"))
375392
.map(|(start, body): (Span, SpannedExpr)| SpannedExpr {
@@ -488,6 +505,7 @@ fn parser<'src>() -> impl Parser<
488505
let_stmt,
489506
assign_stmt,
490507
fn_stmt,
508+
class_stmt,
491509
infinite_loop_stmt,
492510
for_loop_stmt,
493511
while_loop_stmt,

lang/src/vm/value.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ pub enum Value {
2222
start: i64,
2323
end: i64,
2424
inclusive: bool,
25-
}
25+
},
26+
27+
Class {
28+
name: String,
29+
methods: HashMap<String, Value>,
30+
},
2631
}
2732

2833
#[derive(Clone)]
@@ -197,6 +202,7 @@ impl Value {
197202
Value::Range { .. } => "range",
198203
Value::FFILib(_) => "ffi_lib",
199204
Value::FFIFunc(_, _) => "ffi_function",
205+
Value::Class { .. } => "class",
200206
}
201207
}
202208

lang/src/vm/vm.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,16 @@ impl VM {
274274
});
275275
}
276276

277+
Value::Class { name, methods } => {
278+
let args: Vec<Value> = self.stack.drain(self.stack.len() - argc..).collect();
279+
self.stack.pop();
280+
281+
let instance = Value::Instance {
282+
class: name.clone(),
283+
properties: HashMap::new()
284+
};
285+
}
286+
277287
_ => {
278288
return Err(self.runtime_error(format!("{} is not callable", callee.type_name()), span));
279289
}

0 commit comments

Comments
 (0)