Skip to content

Commit f5fabab

Browse files
committed
Templates can now be used as member functions
1 parent fdcea5d commit f5fabab

File tree

8 files changed

+151
-65
lines changed

8 files changed

+151
-65
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "density_function_lang"
3-
version = "2.0.2"
3+
version = "2.1.0"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

src/compiler/ast.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::compiler::lexer::Token;
88
pub enum Stmt {
99
Template {
1010
name: Token,
11+
this: Option<Token>,
1112
args: Vec<Token>,
1213
expr: Expr,
1314
},
@@ -35,10 +36,12 @@ pub enum Stmt {
3536
impl Debug for Stmt {
3637
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3738
match self {
38-
Stmt::Template { name, args, expr } =>
39-
write!(f, "template {}({}) = {:?};", name.source(), args.iter()
40-
.map(|arg| arg.source().to_owned())
41-
.collect::<Vec<String>>().join(", "), expr),
39+
Stmt::Template { name, this, args, expr } =>
40+
write!(f, "template {}({}{}) = {:?};", name.source(),
41+
this.as_ref().map(|this| format!("{}, ", this.source())).unwrap_or_else(|| String::new()),
42+
args.iter()
43+
.map(|arg| arg.source().to_owned())
44+
.collect::<Vec<String>>().join(", "), expr),
4245

4346
Stmt::Function { name, expr } =>
4447
write!(f, "function {} = {:?};", name.source(), expr),
@@ -64,8 +67,6 @@ pub enum Expr {
6467
ConstantString(String),
6568
Identifier(Token),
6669

67-
Group(Box<Expr>),
68-
6970
UnaryOperator {
7071
operator: Token,
7172
expr: Box<Expr>,
@@ -76,8 +77,8 @@ pub enum Expr {
7677
right: Box<Expr>,
7778
},
7879
FunctionCall {
79-
receiver: Option<Box<Expr>>,
80-
name: Token,
80+
callee: Box<Expr>,
81+
paren_left: Token,
8182
args: Vec<Expr>,
8283
},
8384
Member {
@@ -98,17 +99,10 @@ impl Debug for Expr {
9899
Expr::ConstantInt(value) => write!(f, "{}", value),
99100
Expr::ConstantString(value) => write!(f, "\"{}\"", value),
100101
Expr::Identifier(value) => write!(f, "{}", value.source()),
101-
Expr::Group(expr) => write!(f, "{:?}", expr),
102102
Expr::UnaryOperator { operator, expr } => write!(f, "({}{:?})", operator.source(), expr),
103103
Expr::BinaryOperator { left, operator, right } => write!(f, "({:?} {} {:?})", left, operator.source(), right),
104-
Expr::FunctionCall { receiver, name, args } => {
105-
write!(f, "(")?;
106-
107-
if let Some(receiver) = receiver {
108-
write!(f, "{:?}.", receiver)?;
109-
}
110-
111-
write!(f, "{}({}))", name, args.iter()
104+
Expr::FunctionCall { callee, args, .. } => {
105+
write!(f, "({:?}({}))", callee, args.iter()
112106
.map(|expr| format!("{:?}", expr))
113107
.collect::<Vec<String>>().join(", "))
114108
},
@@ -137,6 +131,7 @@ pub struct OutputFunction {
137131
#[derive(Debug)]
138132
pub struct Template {
139133
pub name: String, // Can be identifiers or operator names (like `+`)
134+
pub receiver: bool,
140135
pub args: Vec<String>,
141136
pub expr: Expr,
142137
pub current_modules: Vec<Weak<RefCell<Module>>>,

src/compiler/compiler.rs

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl Compiler {
5454

5555
fn compile_statement(&mut self, stmt: Stmt) {
5656
match stmt {
57-
Stmt::Template { name, args, expr } => self.compile_template(name, args, expr),
57+
Stmt::Template { name, this, args, expr } => self.compile_template(name, this, args, expr),
5858
Stmt::Function { name, expr } => self.compile_function(name, expr),
5959
Stmt::Module { name, statements } => self.compile_module(name, statements),
6060
Stmt::Include { path } => self.compile_include(path),
@@ -63,11 +63,12 @@ impl Compiler {
6363
}
6464
}
6565

66-
fn compile_template(&mut self, name: Token, args: Vec<Token>, expr: Expr) {
66+
fn compile_template(&mut self, name: Token, this: Option<Token>, args: Vec<Token>, expr: Expr) {
6767
let current_module = self.current_module();
6868
let mut current_module = current_module.borrow_mut();
6969

70-
if current_module.templates.iter().any(|template| *template.borrow().name == *name.source() && template.borrow().args.len() == args.len()) {
70+
if current_module.templates.iter().any(|template|
71+
*template.borrow().name == *name.source() && template.borrow().args.len() == args.len() && template.borrow().receiver == this.is_some()) {
7172
self.error_at(*name.start(), "Tried to define multiple templates with the same name", false);
7273
return;
7374
}
@@ -77,6 +78,7 @@ impl Compiler {
7778

7879
current_module.templates.push(Rc::new(RefCell::new(Template {
7980
name: name.source().to_owned(),
81+
receiver: this.is_some(),
8082
args: args.iter().map(|arg| arg.source().to_owned()).collect(),
8183
expr,
8284
current_modules: template_current_modules,
@@ -265,33 +267,31 @@ impl Compiler {
265267
if let Some((_, element)) = self.template_scopes.last().map(|scope| scope.args.iter().rfind(|(arg, _)| *arg == *name.source())).flatten() {
266268
element.clone()
267269
} else {
268-
self.error_at(*name.start(), &format!("Unresolved reference: '{}'", name.source()), false);
269-
JsonElement::Error
270+
self.evaluate_identifier(name)
270271
}
271272
}
272-
Expr::Group(expr) => self.compile_expr(*expr),
273+
// Expr::Group(expr) => self.compile_expr(*expr),
273274
Expr::UnaryOperator { operator, expr } => {
274275
let compiled_expr = self.compile_expr(*expr);
275276

276-
self.evaluate_template(None, operator, vec![compiled_expr])
277+
let pos = *operator.start();
278+
self.evaluate_template(Expr::Identifier(operator), pos, vec![compiled_expr])
277279
},
278280
Expr::BinaryOperator { left, operator, right } => {
279281
let compiled_left = self.compile_expr(*left);
280282
let compiled_right = self.compile_expr(*right);
281283

282-
self.evaluate_template(None, operator, vec![compiled_left, compiled_right])
284+
let pos = *operator.start();
285+
self.evaluate_template(Expr::Identifier(operator), pos, vec![compiled_left, compiled_right])
283286
},
284-
Expr::FunctionCall { receiver, name, args } => {
285-
let compiled_receiver = receiver.map(|receiver| self.compile_expr(*receiver));
287+
Expr::FunctionCall { callee, paren_left, args } => {
286288
let compiled_args = args.into_iter().map(|arg| self.compile_expr(arg)).collect();
287289

288-
self.evaluate_template(compiled_receiver, name, compiled_args)
290+
self.evaluate_template(*callee, *paren_left.start(), compiled_args)
289291
},
290292
Expr::Member { receiver, name } => {
291-
let _ = self.compile_expr(*receiver);
292-
293-
self.error_at(*name.start(), &format!("Unresolved reference: '{}'", name.source()), false);
294-
JsonElement::Error
293+
let compiled_receiver = self.compile_expr(*receiver);
294+
self.evaluate_member(compiled_receiver, name)
295295
},
296296
Expr::Object(fields) => {
297297
JsonElement::Object(fields.into_iter().map(|(name, field)| (name.source().to_owned(), self.compile_expr(field))).collect())
@@ -303,21 +303,32 @@ impl Compiler {
303303
}
304304
}
305305

306-
fn evaluate_template(&mut self, receiver: Option<JsonElement>, name: Token, args: Vec<JsonElement>) -> JsonElement {
307-
if let Some(_) = receiver {
308-
self.error_at(*name.start(), "Member functions are not implemented yet", false);
309-
}
306+
fn evaluate_template(&mut self, callee: Expr, token_pos: TokenPos, args: Vec<JsonElement>) -> JsonElement {
307+
let (receiver, name) = match callee {
308+
Expr::Member { receiver, name} => (Some(self.compile_expr(*receiver)), name),
309+
Expr::Identifier(name) => (None, name),
310+
_ => {
311+
self.error_at(token_pos, "Cannot call non-identifier expression", true);
312+
return JsonElement::Error;
313+
},
314+
};
310315

311-
let template = match self.find_template(&name, args.len()) {
316+
let template = match self.find_template(&name, receiver.as_ref(), args.len()) {
312317
Some(template) => template,
313318
None => {
314319
self.error_at(*name.start(), &format!("Unresolved function call: {}", name.source()), false);
315320
return JsonElement::Error;
316-
},
321+
}
317322
};
318323
let template_borrow = template.borrow();
319324

320325
let mut scope_args = vec![];
326+
// eprintln!("name: {}; template receiver: {}; provided receiver: {}; template args: {:?}; provided args: {:?}",
327+
// &template_borrow.name, template_borrow.receiver, receiver.is_some(), &template_borrow.args, &args);
328+
329+
if let Some(receiver) = receiver {
330+
scope_args.push((String::from("this"), receiver));
331+
}
321332

322333
for i in 0..template_borrow.args.len() {
323334
let name = template_borrow.args[i].clone();
@@ -346,15 +357,22 @@ impl Compiler {
346357
expr
347358
}
348359

349-
fn find_template(&mut self, name: &Token, arg_count: usize) -> Option<Rc<RefCell<Template>>> {
360+
fn find_template(&mut self, name: &Token, receiver: Option<&JsonElement>, arg_count: usize) -> Option<Rc<RefCell<Template>>> {
361+
if let Some(receiver) = receiver {
362+
match receiver {
363+
JsonElement::Module(module) => return Self::find_template_on(module, name, false, arg_count),
364+
_ => {},
365+
}
366+
}
367+
350368
let mut module_index: isize = self.current_module.len() as isize - 1;
351369

352370
while module_index >= -1 {
353371
let module = Rc::clone(if module_index >= 0 {
354372
&self.current_module[module_index as usize]
355373
} else { &self.top_level_module });
356374

357-
if let Some(template) = Self::find_template_on(&module, &name, arg_count) {
375+
if let Some(template) = Self::find_template_on(&module, &name, receiver.is_some(), arg_count) {
358376
return Some(template);
359377
}
360378

@@ -364,16 +382,68 @@ impl Compiler {
364382
None
365383
}
366384

367-
fn find_template_on(module: &Rc<RefCell<Module>>, name: &Token, arg_count: usize) -> Option<Rc<RefCell<Template>>> {
385+
fn find_template_on(module: &Rc<RefCell<Module>>, name: &Token, receiver: bool, arg_count: usize) -> Option<Rc<RefCell<Template>>> {
368386
for template in &module.borrow().templates {
369-
if *template.borrow().name == *name.source() && template.borrow().args.len() == arg_count {
387+
if *template.borrow().name == *name.source() && template.borrow().args.len() == arg_count && (template.borrow().receiver == receiver) {
370388
return Some(Rc::clone(template));
371389
}
372390
}
373391

374392
None
375393
}
376394

395+
fn evaluate_identifier(&mut self, name: Token) -> JsonElement {
396+
let mut module_index: isize = self.current_module.len() as isize - 1;
397+
398+
while module_index >= -1 {
399+
let module = Rc::clone(if module_index >= 0 {
400+
&self.current_module[module_index as usize]
401+
} else { &self.top_level_module });
402+
403+
for template in &module.borrow().templates {
404+
if *template.borrow().name == *name.source() && !template.borrow().receiver {
405+
return JsonElement::Template(Rc::clone(template));
406+
}
407+
}
408+
409+
for sub_module in &module.borrow().sub_modules {
410+
if *sub_module.borrow().name == *name.source() {
411+
return JsonElement::Module(Rc::clone(sub_module));
412+
}
413+
}
414+
415+
module_index -= 1;
416+
}
417+
418+
self.error_at(*name.start(), &format!("Unresolved reference: '{}'", name.source()), false);
419+
JsonElement::Error
420+
}
421+
422+
fn evaluate_member(&mut self, receiver: JsonElement, name: Token) -> JsonElement {
423+
match receiver {
424+
JsonElement::Module(module) => {
425+
for template in &module.borrow().templates {
426+
if *template.borrow().name == *name.source() {
427+
return JsonElement::Template(Rc::clone(template));
428+
}
429+
}
430+
431+
for sub_module in &module.borrow().sub_modules {
432+
if *sub_module.borrow().name == *name.source() {
433+
return JsonElement::Module(Rc::clone(sub_module));
434+
}
435+
}
436+
437+
self.error_at(*name.start(), &format!("Unresolved reference: '{}'", name.source()), false);
438+
JsonElement::Error
439+
},
440+
_ => {
441+
self.error_at(*name.start(), "Tried to get a member of non-module value", true);
442+
JsonElement::Error
443+
},
444+
}
445+
}
446+
377447
fn current_module(&self) -> Rc<RefCell<Module>> {
378448
self.current_module.last().map(|module| Rc::clone(&module)).unwrap_or_else(|| Rc::clone(&self.top_level_module))
379449
}

src/compiler/lexer.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub enum TokenType {
5454
// Keywords
5555
Builtin,
5656
Inline,
57-
Template,
57+
Template, This,
5858
Function,
5959
Module, Include, Import,
6060

@@ -343,7 +343,15 @@ impl<'source> Lexer<'source> {
343343
} else { TokenType::Identifier }
344344
},
345345
'm' => Lexer::check_keyword(name, 1, "module", TokenType::Module),
346-
't' => Lexer::check_keyword(name, 1, "template", TokenType::Template),
346+
't' => {
347+
if let Some(c) = chars.next() {
348+
match c {
349+
'e' => Lexer::check_keyword(name, 2, "template", TokenType::Template),
350+
'h' => Lexer::check_keyword(name, 2, "this", TokenType::This),
351+
_ => TokenType::Identifier,
352+
}
353+
} else { TokenType::Identifier }
354+
},
347355
_ => TokenType::Identifier,
348356
};
349357

0 commit comments

Comments
 (0)