pub fn new_error<L: Into<Span>>(
message: String,
location: L,
code: u16,
) -> Error
Expand description
Creates a new error in the given source file, at the given location, and with the given message and code.
location
will accept any type that is Token
, Delimiter
, or a Span
.
Examples found in repository?
examples/lox/resolver.rs (lines 41-45)
38 fn declare(&mut self, name: &Ident) {
39 if let Some(scope) = self.scopes.last_mut() {
40 if scope.contains_key(name.string()) {
41 self.error(new_error(
42 "Already a variable with this name in scope".to_string(),
43 name,
44 error_codes::SHADOW,
45 ));
46 } else {
47 scope.insert(name.string().to_owned(), false);
48 }
49 }
50 }
51
52 fn define(&mut self, name: &Ident) {
53 if let Some(scope) = self.scopes.last_mut() {
54 scope.insert(name.string().to_owned(), true);
55 }
56 }
57
58 fn resolve_local(&self, name: &Ident, distance: &Cell<Option<usize>>) {
59 for (i, scope) in self.scopes.iter().enumerate().rev() {
60 if scope.contains_key(name.string()) {
61 distance.set(Some(self.scopes.len() - 1 - i));
62 return;
63 }
64 }
65 }
66
67 fn error(&mut self, error: Error) {
68 if let Some(existing_error) = &mut self.error {
69 existing_error.add(error);
70 } else {
71 self.error = Some(error);
72 }
73 }
74
75 fn begin_scope(&mut self) {
76 self.scopes.push(HashMap::new());
77 }
78
79 fn end_scope(&mut self) {
80 self.scopes.pop();
81 }
82}
83
84impl Expr {
85 fn resolve(&self, state: &mut State) {
86 match self {
87 Expr::Assign {
88 name,
89 value,
90 distance,
91 } => {
92 value.resolve(state);
93 state.resolve_local(name, distance);
94 }
95 Expr::Binary(binary) => {
96 binary.left().resolve(state);
97 binary.right().resolve(state);
98 }
99 Expr::Call {
100 callee,
101 paren: _,
102 arguments,
103 } => {
104 callee.resolve(state);
105 for argument in arguments {
106 argument.resolve(state);
107 }
108 }
109 Expr::Get { object, name: _ } => object.resolve(state),
110 Expr::Group(expr) => expr.resolve(state),
111 Expr::Literal(_) => {}
112 Expr::Logical(logical) => {
113 logical.left().resolve(state);
114 logical.right().resolve(state);
115 }
116 Expr::Set {
117 object,
118 name: _,
119 value,
120 } => {
121 object.resolve(state);
122 value.resolve(state);
123 }
124 Expr::Super {
125 keyword,
126 distance,
127 dot: _,
128 method: _,
129 } => {
130 if state.current_class == ClassType::None {
131 state.error(new_error(
132 "Can't use 'super' outside of a class".to_string(),
133 keyword,
134 error_codes::INVALID_SUPER,
135 ));
136 } else if state.current_class == ClassType::Class {
137 state.error(new_error(
138 "Can't use 'super' in a class with no superclass".to_string(),
139 keyword,
140 error_codes::INVALID_SUPER,
141 ));
142 }
143 state.resolve_local(keyword.ident(), distance);
144 }
145 Expr::This { keyword, distance } => {
146 if state.current_class == ClassType::None {
147 state.error(new_error(
148 "Can't use 'this' outside of a class".to_string(),
149 keyword,
150 error_codes::THIS_OUTSIDE_CLASS,
151 ));
152 }
153
154 state.resolve_local(keyword.ident(), distance);
155 }
156 Expr::Unary(unary) => unary.right().resolve(state),
157 Expr::Variable { name, distance } => {
158 if let Some(scope) = state.scopes.last() {
159 if scope.get(name.string()) == Some(&false) {
160 state.error(new_error(
161 "Can't read a variable in its own intialiser".to_string(),
162 name,
163 error_codes::INVALID_INITIALISER,
164 ));
165 }
166 }
167 state.resolve_local(name, distance);
168 }
169 }
170 }
171}
172
173impl Function {
174 fn resolve(&self, state: &mut State, kind: FunctionType) {
175 let enclosing = state.current_function;
176 state.current_function = kind;
177 state.begin_scope();
178 for param in &self.params {
179 state.declare(param);
180 state.define(param);
181 }
182 for stmt in &self.body {
183 stmt.resolve(state);
184 }
185 state.end_scope();
186 state.current_function = enclosing;
187 }
188}
189
190impl Stmt {
191 fn resolve(&self, state: &mut State) {
192 match self {
193 Stmt::Block(stmts) => {
194 state.begin_scope();
195 for stmt in stmts {
196 stmt.resolve(state);
197 }
198 state.end_scope();
199 }
200 Stmt::Class {
201 name,
202 superclass,
203 superclass_distance,
204 methods,
205 } => {
206 let enclosing = state.current_class;
207 state.current_class = ClassType::Class;
208
209 state.declare(name);
210 state.define(name);
211
212 if let Some(superclass) = superclass {
213 if name.string() == superclass.string() {
214 state.error(new_error(
215 "A class can't inherit from itself".to_string(),
216 superclass,
217 error_codes::CYCLICAL_INHERITANCE,
218 ));
219 }
220
221 state.current_class = ClassType::SubClass;
222
223 state.resolve_local(superclass, superclass_distance);
224
225 state.begin_scope();
226 state
227 .scopes
228 .last_mut()
229 .unwrap()
230 .insert("super".to_string(), true);
231 }
232
233 state.begin_scope();
234 state
235 .scopes
236 .last_mut()
237 .unwrap()
238 .insert("this".to_string(), true);
239
240 for method in methods {
241 let kind = if method.name.string() == "init" {
242 FunctionType::Initialiser
243 } else {
244 FunctionType::Method
245 };
246 method.resolve(state, kind);
247 }
248
249 state.end_scope();
250
251 if superclass.is_some() {
252 state.end_scope();
253 }
254
255 state.current_class = enclosing;
256 }
257 Stmt::Expr(expr) | Stmt::Print(expr) => expr.resolve(state),
258 Stmt::Function(function) => {
259 state.declare(&function.name);
260 state.declare(&function.name);
261 function.resolve(state, FunctionType::Function);
262 }
263 Stmt::If {
264 condition,
265 then_branch,
266 else_branch,
267 } => {
268 condition.resolve(state);
269 then_branch.resolve(state);
270 if let Some(else_branch) = else_branch {
271 else_branch.resolve(state);
272 }
273 }
274 Stmt::Return { keyword, value } => {
275 if state.current_function == FunctionType::None {
276 state.error(new_error(
277 "Can't return from top-level code".to_string(),
278 keyword,
279 error_codes::RETURN_OUTSIDE_FUNCTION,
280 ));
281 }
282 if let Some(value) = value {
283 value.resolve(state);
284 }
285 }
286 Stmt::Variable { name, initialiser } => {
287 state.declare(name);
288 if let Some(initialiser) = initialiser {
289 initialiser.resolve(state);
290 }
291 state.define(name);
292 }
293 Stmt::While { condition, body } => {
294 condition.resolve(state);
295 body.resolve(state);
296 }
297 }
298 }
More examples
examples/lox/interpreter.rs (lines 217-221)
210fn get(instance: &'static RefCell<Instance>, name: &Ident) -> Result<Value> {
211 let this = instance.borrow();
212 if let Some(value) = this.fields.get(name.string()) {
213 Ok(value.to_owned())
214 } else if let Some(function) = this.class.find_method(name.string()) {
215 Ok(Value::Function(function.bind(instance)))
216 } else {
217 Err(new_error(
218 format!("Undefined property '{}'", name.string()),
219 name,
220 error_codes::UNDEFINED_NAME,
221 ))
222 }
223}
224
225impl fmt::Debug for Instance {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 f.debug_struct("Instance")
228 .field("class", &self.class.name)
229 .field("fields", &self.fields)
230 .finish()
231 }
232}
233
234#[derive(Debug, Clone, PartialEq)]
235enum Value {
236 Nil,
237 String(String),
238 Number(f64),
239 Bool(bool),
240 Native(NativeFunction),
241 Function(Function),
242 Class(Rc<Class>),
243 Instance(&'static RefCell<Instance>),
244}
245
246fn arity_error(parentheses: &Parentheses, expected: usize, actual: usize) -> Error {
247 new_error(
248 format!("Expected {expected} arguments but got {actual}"),
249 parentheses.span().to_owned(),
250 error_codes::INCORRECT_ARITY,
251 )
252}
253
254impl Value {
255 const fn as_class(&self) -> Option<&Rc<Class>> {
256 if let Value::Class(class) = self {
257 Some(class)
258 } else {
259 None
260 }
261 }
262
263 const fn as_instance(&self) -> Option<&'static RefCell<Instance>> {
264 if let Value::Instance(instance) = self {
265 Some(*instance)
266 } else {
267 None
268 }
269 }
270
271 const fn is_truthy(&self) -> bool {
272 !matches!(self, Value::Nil | Value::Bool(false))
273 }
274
275 fn add(&self, op: &Punct!["+"], other: &Value) -> Result<Value> {
276 match (self, other) {
277 (Value::Number(n1), Value::Number(n2)) => Ok(Value::Number(n1 + n2)),
278 (Value::String(s1), Value::String(s2)) => Ok(Value::String(s1.to_owned() + s2)),
279 _ => Err(new_error(
280 format!("Can't add '{self}' to '{other}'"),
281 op,
282 error_codes::TYPE_ERROR,
283 )),
284 }
285 }
286
287 fn sub(&self, op: &Punct!["-"], other: &Value) -> Result<Value> {
288 if let (Value::Number(n1), Value::Number(n2)) = (self, other) {
289 Ok(Value::Number(n1 - n2))
290 } else {
291 Err(new_error(
292 format!("Can't subtract '{other}' from '{self}'"),
293 op,
294 error_codes::TYPE_ERROR,
295 ))
296 }
297 }
298
299 fn mul(&self, op: &Punct!["*"], other: &Value) -> Result<Value> {
300 if let (Value::Number(n1), Value::Number(n2)) = (self, other) {
301 Ok(Value::Number(n1 * n2))
302 } else {
303 Err(new_error(
304 format!("Can't multiply '{self}' by '{other}'"),
305 op,
306 error_codes::TYPE_ERROR,
307 ))
308 }
309 }
310
311 fn div(&self, op: &Punct!["/"], other: &Value) -> Result<Value> {
312 if let (Value::Number(n1), Value::Number(n2)) = (self, other) {
313 Ok(Value::Number(n1 / n2))
314 } else {
315 Err(new_error(
316 format!("Can't divide '{other}' by '{self}'"),
317 op,
318 error_codes::TYPE_ERROR,
319 ))
320 }
321 }
322
323 fn neg(&self, op: &Punct!["-"]) -> Result<Value> {
324 if let Value::Number(n) = self {
325 Ok(Value::Number(-n))
326 } else {
327 Err(new_error(
328 format!("Can't negate '{self}'"),
329 op,
330 error_codes::TYPE_ERROR,
331 ))
332 }
333 }
334
335 fn cmp<T: Token>(&self, op: &T, other: &Value) -> Result<Ordering> {
336 if self == other {
337 return Ok(Ordering::Equal);
338 }
339
340 match (self, other) {
341 (Value::String(s1), Value::String(s2)) => Ok(s1.cmp(s2).into()),
342 (Value::Number(n1), Value::Number(n2)) => Ok(n1.partial_cmp(n2).into()),
343 (Value::Bool(b1), Value::Bool(b2)) => Ok(b1.cmp(b2).into()),
344 _ => Err(new_error(
345 format!("Can't compare '{self}' with '{other}'"),
346 op,
347 error_codes::TYPE_ERROR,
348 )),
349 }
350 }
351
352 fn call(&self, arguments: Vec<Value>, parentheses: &Parentheses) -> Result<Value> {
353 match self {
354 Value::Native(NativeFunction {
355 function, arity, ..
356 }) => {
357 if *arity != arguments.len() {
358 return Err(arity_error(parentheses, *arity, arguments.len()));
359 }
360 function(arguments)
361 }
362 Value::Function(function) => function.call(arguments, parentheses),
363 Value::Class(class) => {
364 if class.arity() != arguments.len() {
365 return Err(arity_error(parentheses, class.arity(), arguments.len()));
366 }
367
368 let instance = allocate(Instance::new(Rc::clone(class)));
369 if let Some(initialiser) = class.find_method("init") {
370 initialiser.bind(instance).call(arguments, parentheses)?;
371 }
372 Ok(Value::Instance(instance))
373 }
374 Value::Nil
375 | Value::String(_)
376 | Value::Number(_)
377 | Value::Bool(_)
378 | Value::Instance(_) => Err(new_error(
379 format!("Can't call '{self}'"),
380 parentheses.span().clone(),
381 error_codes::TYPE_ERROR,
382 )),
383 }
384 }
385}
386
387impl fmt::Display for Value {
388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389 match self {
390 Value::Nil => f.write_str("nil"),
391 Value::String(s) => f.write_str(s),
392 Value::Number(n) => write!(f, "{n}"),
393 Value::Bool(b) => write!(f, "{b}"),
394 Value::Native(NativeFunction { name, .. }) => write!(f, "<native fn '{name}'>"),
395 Value::Function(Function {
396 declaration: FunctionDecl { name, .. },
397 ..
398 }) => write!(f, "<fn {}>", name.string()),
399 Value::Class(class) => f.write_str(&class.name),
400 Value::Instance(instance) => write!(f, "'{}' instance", instance.borrow().class.name),
401 }
402 }
403}
404
405#[derive(Debug, Clone)]
406struct State {
407 environment: Rc<RefCell<Environment>>,
408 globals: Rc<RefCell<Environment>>,
409}
410
411impl State {
412 fn new() -> Self {
413 let mut values = HashMap::new();
414
415 values.insert(
416 "clock".to_string(),
417 Value::Native(NativeFunction {
418 function: natives::clock,
419 arity: 0,
420 name: "clock",
421 }),
422 );
423
424 let environment = Rc::new(RefCell::new(Environment {
425 values,
426 enclosing: None,
427 sub: vec![],
428 mark: Cell::new(false),
429 }));
430
431 State {
432 environment: Rc::clone(&environment),
433 globals: environment,
434 }
435 }
436
437 #[must_use]
438 fn start_scope(&self) -> State {
439 let environment = Rc::new(RefCell::new(Environment {
440 values: HashMap::new(),
441 enclosing: Some(Rc::clone(&self.environment)),
442 sub: vec![],
443 mark: Cell::new(false),
444 }));
445 self.environment
446 .borrow_mut()
447 .sub
448 .push(Rc::downgrade(&environment));
449 State {
450 environment,
451 globals: Rc::clone(&self.globals),
452 }
453 }
454
455 fn super_scope(self) -> Option<State> {
456 Some(State {
457 environment: Rc::clone(self.environment.borrow().enclosing.as_ref()?),
458 globals: self.globals,
459 })
460 }
461}
462
463fn allocate<T>(value: T) -> &'static RefCell<T> {
464 Box::leak(Box::new(RefCell::new(value)))
465}
466
467struct Environment {
468 values: HashMap<String, Value>,
469 enclosing: Option<Rc<RefCell<Environment>>>,
470 sub: Vec<Weak<RefCell<Environment>>>,
471 mark: Cell<bool>,
472}
473
474impl Environment {
475 fn get(&self, name: &Ident) -> Result<Value> {
476 self.values.get(name.string()).map_or_else(
477 || {
478 self.enclosing.as_ref().map_or_else(
479 || {
480 Err(new_error(
481 format!("Undefined variable '{}'", name.string()),
482 name,
483 error_codes::UNDEFINED_NAME,
484 ))
485 },
486 |enclosing| enclosing.borrow().get(name),
487 )
488 },
489 |value| Ok(value.to_owned()),
490 )
491 }
492
493 fn get_at(&self, name: &Ident, distance: usize) -> Result<Value> {
494 if distance == 0 {
495 self.get(name)
496 } else {
497 self.enclosing
498 .as_ref()
499 .unwrap()
500 .borrow()
501 .get_at(name, distance - 1)
502 }
503 }
504
505 fn define(&mut self, name: String, value: Value) {
506 self.values.insert(name, value);
507 }
508
509 fn assign(&mut self, name: &Ident, value: Value) -> Result<()> {
510 if self.values.contains_key(name.string()) {
511 self.values.insert(name.string().clone(), value);
512 Ok(())
513 } else if let Some(enclosing) = &self.enclosing {
514 enclosing.borrow_mut().assign(name, value)
515 } else {
516 Err(new_error(
517 format!("Undefined variable '{}'", name.string()),
518 name,
519 error_codes::UNDEFINED_NAME,
520 ))
521 }
522 }
523
524 fn assign_at(&mut self, name: &Ident, value: Value, distance: usize) -> Result<()> {
525 if distance == 0 {
526 self.assign(name, value)
527 } else {
528 self.enclosing
529 .as_ref()
530 .unwrap()
531 .borrow_mut()
532 .assign_at(name, value, distance - 1)
533 }
534 }
535}
536
537struct EnvValuesDebug<'a>(&'a HashMap<String, Value>);
538
539impl fmt::Debug for EnvValuesDebug<'_> {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 f.debug_map()
542 .entries(self.0.iter().map(|(k, v)| (k, v.to_string())))
543 .finish()
544 }
545}
546
547impl fmt::Debug for Environment {
548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549 f.debug_struct("Environment")
550 .field("values", &EnvValuesDebug(&self.values))
551 .field("enclosing", &self.enclosing)
552 .field("sub", &self.sub)
553 .field("mark", &self.mark)
554 .finish()
555 }
556}
557
558impl Binary {
559 fn evaluate(&self, state: &State) -> Result<Value> {
560 match self {
561 Binary::Mul(left, op, right) => left.evaluate(state)?.mul(op, &right.evaluate(state)?),
562 Binary::Div(left, op, right) => left.evaluate(state)?.div(op, &right.evaluate(state)?),
563 Binary::Add(left, op, right) => left.evaluate(state)?.add(op, &right.evaluate(state)?),
564 Binary::Sub(left, op, right) => left.evaluate(state)?.sub(op, &right.evaluate(state)?),
565 Binary::Equal(left, _, right) => {
566 Ok(Value::Bool(left.evaluate(state)? == right.evaluate(state)?))
567 }
568 Binary::NotEqual(left, _, right) => {
569 Ok(Value::Bool(left.evaluate(state)? != right.evaluate(state)?))
570 }
571 Binary::Greater(left, op, right) => Ok(Value::Bool(
572 left.evaluate(state)?.cmp(op, &right.evaluate(state)?)?.gt(),
573 )),
574 Binary::GreaterEqual(left, op, right) => Ok(Value::Bool(
575 left.evaluate(state)?.cmp(op, &right.evaluate(state)?)?.ge(),
576 )),
577 Binary::Less(left, op, right) => Ok(Value::Bool(
578 left.evaluate(state)?.cmp(op, &right.evaluate(state)?)?.lt(),
579 )),
580 Binary::LessEqual(left, op, right) => Ok(Value::Bool(
581 left.evaluate(state)?.cmp(op, &right.evaluate(state)?)?.le(),
582 )),
583 }
584 }
585}
586
587impl Literal {
588 fn evaluate(&self) -> Value {
589 match self {
590 Literal::False(_) => Value::Bool(false),
591 Literal::Float(value) => Value::Number(value.value()),
592 #[allow(clippy::cast_precision_loss)]
593 Literal::Int(value) => Value::Number(value.value() as f64),
594 Literal::Nil(_) => Value::Nil,
595 Literal::String(string) => Value::String(string.string().clone()),
596 Literal::True(_) => Value::Bool(true),
597 }
598 }
599}
600
601impl Logical {
602 fn evaluate(&self, state: &State) -> Result<Value> {
603 match self {
604 Logical::And(left, _, right) => {
605 let left = left.evaluate(state)?;
606 if left.is_truthy() {
607 Ok(left)
608 } else {
609 right.evaluate(state)
610 }
611 }
612 Logical::Or(left, _, right) => {
613 let left = left.evaluate(state)?;
614 if left.is_truthy() {
615 right.evaluate(state)
616 } else {
617 Ok(left)
618 }
619 }
620 }
621 }
622}
623
624impl Unary {
625 fn evaluate(&self, state: &State) -> Result<Value> {
626 match self {
627 Unary::Neg(op, expr) => expr.evaluate(state)?.neg(op),
628 Unary::Not(_, expr) => Ok(Value::Bool(!expr.evaluate(state)?.is_truthy())),
629 }
630 }
631}
632
633impl Expr {
634 fn evaluate(&self, state: &State) -> Result<Value> {
635 match self {
636 Expr::Assign {
637 name,
638 value,
639 distance,
640 } => {
641 let value = value.evaluate(state)?;
642 if let Some(distance) = distance.get() {
643 state
644 .environment
645 .borrow_mut()
646 .assign_at(name, value.clone(), distance)?;
647 } else {
648 state.globals.borrow_mut().assign(name, value.clone())?;
649 }
650 Ok(value)
651 }
652 Expr::Binary(binary) => binary.evaluate(state),
653 Expr::Call {
654 callee,
655 paren,
656 arguments,
657 } => {
658 let callee = callee.evaluate(state)?;
659 let mut evaluated_args = Vec::with_capacity(arguments.len());
660 for arg in arguments {
661 evaluated_args.push(arg.evaluate(state)?);
662 }
663 callee.call(evaluated_args, paren)
664 }
665 Expr::Get { object, name } => {
666 if let Value::Instance(instance) = object.evaluate(state)? {
667 get(instance, name)
668 } else {
669 Err(new_error(
670 "Only instances have properties".to_string(),
671 name,
672 error_codes::TYPE_ERROR,
673 ))
674 }
675 }
676 Expr::Group(expr) => expr.evaluate(state),
677 Expr::Literal(literal) => Ok(literal.evaluate()),
678 Expr::Logical(logical) => logical.evaluate(state),
679 Expr::Set {
680 object,
681 name,
682 value,
683 } => {
684 if let Value::Instance(instance) = object.evaluate(state)? {
685 let value = value.evaluate(state)?;
686 instance.borrow_mut().set(name, value.clone());
687 Ok(value)
688 } else {
689 Err(new_error(
690 "Only instances have fields".to_string(),
691 name,
692 error_codes::TYPE_ERROR,
693 ))
694 }
695 }
696 Expr::Super {
697 keyword,
698 distance,
699 dot: _,
700 method,
701 } => {
702 let superclass = state
703 .environment
704 .borrow()
705 .get_at(keyword.ident(), distance.clone().into_inner().unwrap())?;
706
707 let object = state.environment.borrow().get_at(
708 &Ident::new("this".to_string(), keyword.span().clone()),
709 distance.clone().into_inner().unwrap() - 1,
710 )?;
711
712 superclass
713 .as_class()
714 .unwrap()
715 .find_method(method.string())
716 .map_or_else(
717 || {
718 Err(new_error(
719 format!("Undefined property '{}'", method.string()),
720 method,
721 error_codes::UNDEFINED_NAME,
722 ))
723 },
724 |method| Ok(Value::Function(method.bind(object.as_instance().unwrap()))),
725 )
726 }
727 Expr::This { keyword, distance } => distance.get().map_or_else(
728 || state.globals.borrow().get(keyword.ident()),
729 |distance| state.environment.borrow().get_at(keyword.ident(), distance),
730 ),
731 Expr::Unary(unary) => unary.evaluate(state),
732 Expr::Variable { name, distance } => distance.get().map_or_else(
733 || state.globals.borrow().get(name),
734 |distance| state.environment.borrow().get_at(name, distance),
735 ),
736 }
737 }
738}
739
740macro_rules! propagate_return {
741 ( $expr:expr ) => {
742 if let Some(_tmp) = $expr {
743 return Ok(Some(_tmp));
744 }
745 };
746}
747
748impl Stmt {
749 fn execute(&self, state: &State) -> Result<Option<Value>> {
750 match self {
751 Stmt::Block(stmts) => {
752 let inner_state = state.start_scope();
753 for stmt in stmts {
754 propagate_return!(stmt.execute(&inner_state)?);
755 }
756 }
757 Stmt::Class {
758 name,
759 superclass,
760 superclass_distance,
761 methods,
762 } => {
763 let superclass = if let Some(superclass_name) = superclass {
764 let superclass = Expr::Variable {
765 name: superclass_name.clone(),
766 distance: superclass_distance.clone(),
767 }
768 .evaluate(state)?;
769 if let Value::Class(superclass) = superclass {
770 Some(superclass)
771 } else {
772 return Err(new_error(
773 "Superclass must be a class".to_string(),
774 superclass_name,
775 error_codes::INHERIT_FROM_VALUE,
776 ));
777 }
778 } else {
779 None
780 };
781
782 state
783 .environment
784 .borrow_mut()
785 .define(name.string().to_owned(), Value::Nil);
786
787 let superclass_is_some = superclass.is_some();
788 let mut state = superclass.as_ref().map_or_else(
789 || state.clone(),
790 |superclass| {
791 let state = state.start_scope();
792 state
793 .environment
794 .borrow_mut()
795 .define("super".to_string(), Value::Class(Rc::clone(superclass)));
796 state
797 },
798 );
799
800 let methods = methods
801 .iter()
802 .map(|declaration| {
803 (
804 declaration.name.string().to_owned(),
805 Function::new(
806 declaration.clone(),
807 state.clone(),
808 declaration.name.string() == "init",
809 ),
810 )
811 })
812 .collect();
813 let class = Class::new(name.string().to_owned(), superclass, methods);
814
815 if superclass_is_some {
816 state = state.super_scope().unwrap();
817 }
818
819 state
820 .environment
821 .borrow_mut()
822 .assign(name, Value::Class(Rc::new(class)))?;
823 }
824 Stmt::Expr(expr) => {
825 expr.evaluate(state)?;
826 }
827 Stmt::Function(function) => {
828 let value =
829 Value::Function(Function::new(function.to_owned(), state.clone(), false));
830 state
831 .environment
832 .borrow_mut()
833 .define(function.name.string().to_owned(), value);
834 }
835 Stmt::If {
836 condition,
837 then_branch,
838 else_branch,
839 } => {
840 if condition.evaluate(state)?.is_truthy() {
841 propagate_return!(then_branch.execute(state)?);
842 } else if let Some(else_branch) = else_branch {
843 propagate_return!(else_branch.execute(state)?);
844 }
845 }
846 Stmt::Print(expr) => {
847 let value = expr.evaluate(state)?;
848 println!("{value}");
849 }
850 Stmt::Return { keyword: _, value } => {
851 return Ok(Some(
852 value
853 .as_ref()
854 .map_or(Ok(Value::Nil), |v| v.evaluate(state))?,
855 ));
856 }
857 Stmt::Variable { name, initialiser } => {
858 let value = if let Some(initialiser) = initialiser {
859 initialiser.evaluate(state)?
860 } else {
861 Value::Nil
862 };
863 state
864 .environment
865 .borrow_mut()
866 .define(name.string().to_owned(), value);
867 }
868 Stmt::While { condition, body } => {
869 while condition.evaluate(state)?.is_truthy() {
870 propagate_return!(body.execute(state)?);
871 }
872 }
873 }
874
875 Ok(None)
876 }