Compare commits
No commits in common. "096d8d00bc9f7498c60a583630b0eab1c9ed41a0" and "35fc591c76ba68e94f9a25a0095f653cf263e651" have entirely different histories.
096d8d00bc
...
35fc591c76
|
@ -59,7 +59,7 @@ impl<'a> Chunk<'a> {
|
||||||
spans: vec![],
|
spans: vec![],
|
||||||
strings: vec![],
|
strings: vec![],
|
||||||
keywords: vec![
|
keywords: vec![
|
||||||
"nil", "bool", "number", "keyword", "string", "tuple", "list", "dict", "box", "fn",
|
"nil", "bool", "number", "keyword", "string", "tuple", "list", "",
|
||||||
],
|
],
|
||||||
nodes: vec![],
|
nodes: vec![],
|
||||||
ast: &ast.0,
|
ast: &ast.0,
|
||||||
|
|
68
src/main.rs
68
src/main.rs
|
@ -1,68 +0,0 @@
|
||||||
use chumsky::{input::Stream, prelude::*};
|
|
||||||
|
|
||||||
mod spans;
|
|
||||||
|
|
||||||
mod lexer;
|
|
||||||
use crate::lexer::lexer;
|
|
||||||
|
|
||||||
mod parser;
|
|
||||||
use crate::parser::parser;
|
|
||||||
|
|
||||||
mod validator;
|
|
||||||
|
|
||||||
mod compiler;
|
|
||||||
use crate::compiler::Chunk;
|
|
||||||
|
|
||||||
mod value;
|
|
||||||
|
|
||||||
mod vm;
|
|
||||||
use vm::Vm;
|
|
||||||
|
|
||||||
pub fn run(src: &'static str) {
|
|
||||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
|
||||||
if !lex_errs.is_empty() {
|
|
||||||
println!("{:?}", lex_errs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = tokens.unwrap();
|
|
||||||
|
|
||||||
let (parse_result, parse_errors) = parser()
|
|
||||||
.parse(Stream::from_iter(tokens).map((0..src.len()).into(), |(t, s)| (t, s)))
|
|
||||||
.into_output_errors();
|
|
||||||
if !parse_errors.is_empty() {
|
|
||||||
println!("{:?}", parse_errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed = parse_result.unwrap();
|
|
||||||
|
|
||||||
let mut chunk = Chunk::new(&parsed, "test", src);
|
|
||||||
chunk.compile();
|
|
||||||
chunk.disassemble();
|
|
||||||
|
|
||||||
let mut vm = Vm::new(&chunk);
|
|
||||||
let result = vm.interpret();
|
|
||||||
let output = match result {
|
|
||||||
Ok(val) => val.show(&chunk),
|
|
||||||
Err(panic) => format!("{:?}", panic),
|
|
||||||
};
|
|
||||||
println!("{output}");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let src = "
|
|
||||||
if false
|
|
||||||
then {
|
|
||||||
:foo
|
|
||||||
:bar
|
|
||||||
:baz
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
}
|
|
||||||
";
|
|
||||||
run(src);
|
|
||||||
}
|
|
214
src/validator.rs
214
src/validator.rs
|
@ -1,5 +1,5 @@
|
||||||
use crate::parser::*;
|
use crate::parser::*;
|
||||||
use crate::spans::{Span, Spanned};
|
use crate::spans::Span;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
@ -143,13 +143,6 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit(&mut self, node: &'a Spanned<Ast>) {
|
|
||||||
let (expr, span) = node;
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(&mut self) {
|
pub fn validate(&mut self) {
|
||||||
use Ast::*;
|
use Ast::*;
|
||||||
let root = self.ast;
|
let root = self.ast;
|
||||||
|
@ -186,13 +179,18 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
let to = self.locals.len();
|
let to = self.locals.len();
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
for line in block.iter().take(block.len() - 1) {
|
for (expr, span) in block.iter().take(block.len() - 1) {
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
self.visit(line);
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (expr, span) = block.last().unwrap();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
self.visit(block.last().unwrap());
|
self.validate();
|
||||||
|
|
||||||
let block_bindings = self.locals.split_off(to);
|
let block_bindings = self.locals.split_off(to);
|
||||||
|
|
||||||
|
@ -209,12 +207,22 @@ impl<'a> Validator<'a> {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
|
|
||||||
self.visit(cond.as_ref());
|
let (expr, span) = cond.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
// pass through tailpos only to then/else
|
// pass through tailpos only to then/else
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
self.visit(then.as_ref());
|
let (expr, span) = then.as_ref();
|
||||||
self.visit(r#else.as_ref());
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
|
let (expr, span) = r#else.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
Tuple(members) => {
|
Tuple(members) => {
|
||||||
if members.is_empty() {
|
if members.is_empty() {
|
||||||
|
@ -222,8 +230,10 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for member in members {
|
for (expr, span) in members {
|
||||||
self.visit(member);
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
|
@ -234,8 +244,10 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for arg in args {
|
for (expr, span) in args {
|
||||||
self.visit(arg);
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
self.status.has_placeholder = false;
|
self.status.has_placeholder = false;
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
|
@ -255,21 +267,30 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for member in list {
|
for (expr, span) in list {
|
||||||
self.visit(member);
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
Pair(_, value) => self.visit(value.as_ref()),
|
Pair(_, value) => {
|
||||||
|
let (expr, span) = value.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
}
|
||||||
Dict(dict) => {
|
Dict(dict) => {
|
||||||
if dict.is_empty() {
|
if dict.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for pair in dict {
|
for (expr, span) in dict {
|
||||||
self.visit(pair)
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
|
@ -278,16 +299,31 @@ impl<'a> Validator<'a> {
|
||||||
// check arity against fn info if first term is word and second term is args
|
// check arity against fn info if first term is word and second term is args
|
||||||
Synthetic(first, second, rest) => {
|
Synthetic(first, second, rest) => {
|
||||||
match (&first.0, &second.0) {
|
match (&first.0, &second.0) {
|
||||||
(Ast::Word(_), Ast::Keyword(_)) => self.visit(first.as_ref()),
|
(Ast::Word(_), Ast::Keyword(_)) => {
|
||||||
|
let (expr, span) = first.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
}
|
||||||
(Ast::Keyword(_), Ast::Arguments(args)) => {
|
(Ast::Keyword(_), Ast::Arguments(args)) => {
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
self.err("called keywords may only take one argument".to_string())
|
self.err("called keywords may only take one argument".to_string())
|
||||||
}
|
}
|
||||||
self.visit(second.as_ref());
|
let (expr, span) = second.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
(Ast::Word(name), Ast::Arguments(args)) => {
|
(Ast::Word(name), Ast::Arguments(args)) => {
|
||||||
self.visit(first.as_ref());
|
let (expr, span) = first.as_ref();
|
||||||
self.visit(second.as_ref());
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
|
let (expr, span) = second.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
//TODO: check arities of prelude fns, too
|
//TODO: check arities of prelude fns, too
|
||||||
let fn_binding = self.bound(name);
|
let fn_binding = self.bound(name);
|
||||||
|
@ -301,20 +337,32 @@ impl<'a> Validator<'a> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
for term in rest {
|
for term in rest {
|
||||||
self.visit(term);
|
let (expr, span) = term;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WhenClause(cond, body) => {
|
WhenClause(cond, body) => {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
self.visit(cond.as_ref());
|
let (expr, span) = cond.as_ref();
|
||||||
//pass through tail position for when bodies
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
self.visit(body.as_ref());
|
let (expr, span) = body.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
When(clauses) => {
|
When(clauses) => {
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
self.visit(clause);
|
let (expr, span) = clause;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,30 +374,54 @@ impl<'a> Validator<'a> {
|
||||||
} else {
|
} else {
|
||||||
self.bind(name.to_string());
|
self.bind(name.to_string());
|
||||||
}
|
}
|
||||||
self.visit(boxed.as_ref());
|
let (expr, span) = boxed.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
Let(lhs, rhs) => {
|
Let(lhs, rhs) => {
|
||||||
self.visit(rhs.as_ref());
|
let (expr, span) = rhs.as_ref();
|
||||||
self.visit(lhs.as_ref());
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
|
let (expr, span) = lhs.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
MatchClause(pattern, guard, body) => {
|
MatchClause(pattern, guard, body) => {
|
||||||
let to = self.locals.len();
|
let to = self.locals.len();
|
||||||
|
|
||||||
self.visit(pattern.as_ref());
|
let (patt, span) = pattern.as_ref();
|
||||||
|
self.ast = patt;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
if let Some(guard) = guard.as_ref() {
|
if let Some((expr, span)) = guard.as_ref() {
|
||||||
self.visit(guard);
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit(body.as_ref());
|
let (expr, span) = body.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
self.locals.truncate(to);
|
self.locals.truncate(to);
|
||||||
}
|
}
|
||||||
Match(scrutinee, clauses) => {
|
Match(scrutinee, clauses) => {
|
||||||
self.visit(scrutinee.as_ref());
|
let (expr, span) = scrutinee.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
self.visit(clause);
|
let (expr, span) = clause;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnDeclaration(name) => {
|
FnDeclaration(name) => {
|
||||||
|
@ -416,7 +488,10 @@ impl<'a> Validator<'a> {
|
||||||
Panic(msg) => {
|
Panic(msg) => {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
self.visit(msg.as_ref());
|
let (expr, span) = msg.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
// TODO: fix the tail call here?
|
// TODO: fix the tail call here?
|
||||||
|
@ -425,23 +500,39 @@ impl<'a> Validator<'a> {
|
||||||
return self.err("do expressions must have at least two terms".to_string());
|
return self.err("do expressions must have at least two terms".to_string());
|
||||||
}
|
}
|
||||||
for term in terms.iter().take(terms.len() - 1) {
|
for term in terms.iter().take(terms.len() - 1) {
|
||||||
self.visit(term);
|
let (expr, span) = term;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
let last = terms.last().unwrap();
|
|
||||||
self.visit(last);
|
let (expr, span) = terms.last().unwrap();
|
||||||
if matches!(last.0, Ast::Recur(_)) {
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
if matches!(expr, Ast::Recur(_)) {
|
||||||
self.err("`recur` may not be used in `do` forms".to_string());
|
self.err("`recur` may not be used in `do` forms".to_string());
|
||||||
}
|
}
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
Repeat(times, body) => {
|
Repeat(times, body) => {
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
self.visit(times.as_ref());
|
let (expr, span) = times.as_ref();
|
||||||
self.visit(body.as_ref());
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
|
let (expr, span) = body.as_ref();
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
Loop(with, body) => {
|
Loop(with, body) => {
|
||||||
self.visit(with.as_ref());
|
let (expr, span) = with.as_ref();
|
||||||
|
self.span = *span;
|
||||||
|
self.ast = expr;
|
||||||
|
self.validate();
|
||||||
|
|
||||||
let Ast::Tuple(input) = &with.0 else {
|
let Ast::Tuple(input) = expr else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -497,7 +588,10 @@ impl<'a> Validator<'a> {
|
||||||
|
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.visit(arg);
|
let (expr, span) = arg;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WordPattern(name) => match self.bound(name) {
|
WordPattern(name) => match self.bound(name) {
|
||||||
|
@ -560,15 +654,25 @@ impl<'a> Validator<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for term in terms.iter().take(terms.len() - 1) {
|
for term in terms.iter().take(terms.len() - 1) {
|
||||||
self.visit(term);
|
let (patt, span) = term;
|
||||||
|
self.ast = patt;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status.last_term = true;
|
self.status.last_term = true;
|
||||||
let last = terms.last().unwrap();
|
let (patt, span) = terms.last().unwrap();
|
||||||
self.visit(last);
|
self.ast = patt;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
self.status.last_term = false;
|
self.status.last_term = false;
|
||||||
}
|
}
|
||||||
PairPattern(_, patt) => self.visit(patt.as_ref()),
|
PairPattern(_, patt) => {
|
||||||
|
let (patt, span) = patt.as_ref();
|
||||||
|
self.ast = patt;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
}
|
||||||
// terminals can never be invalid
|
// terminals can never be invalid
|
||||||
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) => (),
|
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) => (),
|
||||||
// terminal patterns can never be invalid
|
// terminal patterns can never be invalid
|
||||||
|
|
87
src/vm.rs
87
src/vm.rs
|
@ -1,87 +0,0 @@
|
||||||
use crate::compiler::{Chunk, Op};
|
|
||||||
use crate::parser::Ast;
|
|
||||||
use crate::spans::Spanned;
|
|
||||||
use crate::value::Value;
|
|
||||||
use chumsky::prelude::SimpleSpan;
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct Panic {
|
|
||||||
pub input: &'static str,
|
|
||||||
pub src: &'static str,
|
|
||||||
pub msg: String,
|
|
||||||
pub span: SimpleSpan,
|
|
||||||
pub trace: Vec<Trace>,
|
|
||||||
pub extra: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct Trace {
|
|
||||||
pub callee: Spanned<Ast>,
|
|
||||||
pub caller: Spanned<Ast>,
|
|
||||||
pub function: Value,
|
|
||||||
pub arguments: Value,
|
|
||||||
pub input: &'static str,
|
|
||||||
pub src: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Vm<'a> {
|
|
||||||
pub stack: Vec<Value>,
|
|
||||||
pub chunk: &'a Chunk<'a>,
|
|
||||||
pub ip: usize,
|
|
||||||
pub bindings: Vec<(u8, usize)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
|
||||||
pub fn new(chunk: &'a Chunk) -> Vm<'a> {
|
|
||||||
Vm {
|
|
||||||
chunk,
|
|
||||||
stack: vec![],
|
|
||||||
ip: 0,
|
|
||||||
bindings: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, value: Value) {
|
|
||||||
self.stack.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Value {
|
|
||||||
self.stack.pop().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interpret(&mut self) -> Result<Value, Panic> {
|
|
||||||
let byte = self.chunk.bytecode[self.ip];
|
|
||||||
let op = Op::from_u8(byte).unwrap();
|
|
||||||
use Op::*;
|
|
||||||
match op {
|
|
||||||
Return => Ok(self.stack.pop().unwrap()),
|
|
||||||
Constant => {
|
|
||||||
let const_idx = self.chunk.bytecode[self.ip + 1];
|
|
||||||
let value = self.chunk.constants[const_idx as usize].clone();
|
|
||||||
self.push(value);
|
|
||||||
self.ip += 2;
|
|
||||||
self.interpret()
|
|
||||||
}
|
|
||||||
Jump => {
|
|
||||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
|
||||||
self.ip += jump_len as usize;
|
|
||||||
self.interpret()
|
|
||||||
}
|
|
||||||
JumpIfFalse => {
|
|
||||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
|
||||||
let cond = self.stack.pop().unwrap();
|
|
||||||
match cond {
|
|
||||||
Value::Nil | Value::False => {
|
|
||||||
self.ip += jump_len as usize + 2;
|
|
||||||
self.interpret()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.ip += 2;
|
|
||||||
self.interpret()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user