[fine] Panic embeds description, start match
This commit is contained in:
parent
548d9387d6
commit
9ce5794c30
3 changed files with 94 additions and 35 deletions
|
|
@ -17,7 +17,7 @@ pub const EXTERN_USER_FIRST: usize = 100000;
|
||||||
// But I'm not cool.
|
// But I'm not cool.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
Panic,
|
Panic(usize),
|
||||||
|
|
||||||
BoolNot,
|
BoolNot,
|
||||||
Call(usize),
|
Call(usize),
|
||||||
|
|
@ -173,6 +173,22 @@ impl<'a> Compiler<'a> {
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inst_panic<T>(&mut self, description: T) -> Instruction
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
let index = self.add_string(description.into());
|
||||||
|
Instruction::Panic(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_panic<T>(&mut self, description: T) -> usize
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
let instruction = self.inst_panic(description);
|
||||||
|
self.push(instruction)
|
||||||
|
}
|
||||||
|
|
||||||
fn patch(&mut self, i: usize, f: impl FnOnce(usize) -> Instruction) {
|
fn patch(&mut self, i: usize, f: impl FnOnce(usize) -> Instruction) {
|
||||||
let index = self.function.instructions.len();
|
let index = self.function.instructions.len();
|
||||||
self.function.instructions[i] = f(index);
|
self.function.instructions[i] = f(index);
|
||||||
|
|
@ -226,12 +242,12 @@ macro_rules! ice {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! inst_panic {
|
// macro_rules! inst_panic {
|
||||||
($($t:tt)+) => {{
|
// ($($t:tt)+) => {{
|
||||||
// eprintln!($($t)*);
|
// // eprintln!($($t)*);
|
||||||
Instruction::Panic
|
// Instruction::Panic
|
||||||
}};
|
// }};
|
||||||
}
|
// }
|
||||||
|
|
||||||
// macro_rules! ice {
|
// macro_rules! ice {
|
||||||
// ($compiler:expr, $tr:expr, $($t:tt)*) => {{}};
|
// ($compiler:expr, $tr:expr, $($t:tt)*) => {{}};
|
||||||
|
|
@ -318,11 +334,12 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
|
||||||
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
|
TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree),
|
||||||
TreeKind::SelfReference => compile_self_reference(c),
|
TreeKind::SelfReference => compile_self_reference(c),
|
||||||
TreeKind::UnaryExpression => compile_unary_operator(c, t, tree),
|
TreeKind::UnaryExpression => compile_unary_operator(c, t, tree),
|
||||||
|
TreeKind::MatchExpression => compile_match_expression(c, tree),
|
||||||
|
|
||||||
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
|
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
|
||||||
};
|
};
|
||||||
if matches!(cr, None) {
|
if matches!(cr, None) {
|
||||||
c.push(inst_panic!("panic compiling expression {:?}", tree));
|
c.push_panic(format!("panic compiling expression {:?}", tree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +359,7 @@ fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
let index = c.add_string(result);
|
let index = c.add_string(result);
|
||||||
c.push(Instruction::PushString(index))
|
c.push(Instruction::PushString(index))
|
||||||
}
|
}
|
||||||
Type::Error => c.push(inst_panic!("compiling literal {:?}", tr)),
|
Type::Error => c.push_panic(format!("compiling literal {:?}", tr)),
|
||||||
_ => ice!(c, t, "unsupported literal type: {t:?}"),
|
_ => ice!(c, t, "unsupported literal type: {t:?}"),
|
||||||
};
|
};
|
||||||
OK
|
OK
|
||||||
|
|
@ -412,10 +429,10 @@ where
|
||||||
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
let op = tr.nth_token(1)?;
|
let op = tr.nth_token(1)?;
|
||||||
match op.kind {
|
match op.kind {
|
||||||
TokenKind::Plus => compile_simple_binary_expression(c, tr, |_, t| match t {
|
TokenKind::Plus => compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::FloatAdd,
|
Type::F64 => Instruction::FloatAdd,
|
||||||
Type::String => Instruction::StringAdd,
|
Type::String => Instruction::StringAdd,
|
||||||
_ => inst_panic!("panic adding {}", t),
|
_ => c.inst_panic(format!("panic adding {}", t)),
|
||||||
}),
|
}),
|
||||||
TokenKind::Minus => {
|
TokenKind::Minus => {
|
||||||
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatSubtract)
|
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatSubtract)
|
||||||
|
|
@ -427,30 +444,30 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatDivide)
|
compile_simple_binary_expression(c, tr, |_, _| Instruction::FloatDivide)
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenKind::Less => compile_simple_binary_expression(c, tr, |_, t| match t {
|
TokenKind::Less => compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::LessFloat,
|
Type::F64 => Instruction::LessFloat,
|
||||||
Type::String => Instruction::LessString,
|
Type::String => Instruction::LessString,
|
||||||
_ => inst_panic!("panic less {}", t),
|
_ => c.inst_panic(format!("panic less {}", t)),
|
||||||
}),
|
}),
|
||||||
TokenKind::LessEqual => {
|
TokenKind::LessEqual => {
|
||||||
compile_simple_binary_expression(c, tr, |_, t| match t {
|
compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::GreaterFloat,
|
Type::F64 => Instruction::GreaterFloat,
|
||||||
Type::String => Instruction::GreaterString,
|
Type::String => Instruction::GreaterString,
|
||||||
_ => inst_panic!("panic less equal {}", t),
|
_ => c.inst_panic(format!("panic less equal {}", t)),
|
||||||
});
|
});
|
||||||
c.push(Instruction::BoolNot);
|
c.push(Instruction::BoolNot);
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
TokenKind::Greater => compile_simple_binary_expression(c, tr, |_, t| match t {
|
TokenKind::Greater => compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::GreaterFloat,
|
Type::F64 => Instruction::GreaterFloat,
|
||||||
Type::String => Instruction::GreaterString,
|
Type::String => Instruction::GreaterString,
|
||||||
_ => inst_panic!("panic greater {}", t),
|
_ => c.inst_panic(format!("panic greater {}", t)),
|
||||||
}),
|
}),
|
||||||
TokenKind::GreaterEqual => {
|
TokenKind::GreaterEqual => {
|
||||||
compile_simple_binary_expression(c, tr, |_, t| match t {
|
compile_simple_binary_expression(c, tr, |c, t| match t {
|
||||||
Type::F64 => Instruction::LessFloat,
|
Type::F64 => Instruction::LessFloat,
|
||||||
Type::String => Instruction::LessString,
|
Type::String => Instruction::LessString,
|
||||||
_ => inst_panic!("panic greater equal {}", t),
|
_ => c.inst_panic(format!("panic greater equal {}", t)),
|
||||||
});
|
});
|
||||||
c.push(Instruction::BoolNot);
|
c.push(Instruction::BoolNot);
|
||||||
OK
|
OK
|
||||||
|
|
@ -519,7 +536,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Type::F64 => Instruction::EqFloat,
|
Type::F64 => Instruction::EqFloat,
|
||||||
Type::String => Instruction::EqString,
|
Type::String => Instruction::EqString,
|
||||||
Type::Bool => Instruction::EqBool, // ?
|
Type::Bool => Instruction::EqBool, // ?
|
||||||
_ => inst_panic!("panic comparing {}", arg_type),
|
_ => c.inst_panic(format!("panic comparing {}", arg_type)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -579,11 +596,11 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
Declaration::ExternFunction { .. } => c.inst_panic("store ext"),
|
||||||
Declaration::Function { .. } => inst_panic!("store func"),
|
Declaration::Function { .. } => c.inst_panic("store func"),
|
||||||
Declaration::Class { .. } => inst_panic!("store class"),
|
Declaration::Class { .. } => c.inst_panic("store class"),
|
||||||
Declaration::ImportedModule { .. } => inst_panic!("store import"),
|
Declaration::ImportedModule { .. } => c.inst_panic("store import"),
|
||||||
Declaration::ImportedDeclaration { .. } => inst_panic!("store import decl"),
|
Declaration::ImportedDeclaration { .. } => c.inst_panic("store import decl"),
|
||||||
};
|
};
|
||||||
c.push(instruction);
|
c.push(instruction);
|
||||||
OK
|
OK
|
||||||
|
|
@ -672,6 +689,36 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
|
||||||
|
compile_expression(c, tree.nth_tree(1)?);
|
||||||
|
|
||||||
|
let mut patches = Vec::new();
|
||||||
|
let match_body = tree.child_tree_of_kind(c.syntax, TreeKind::MatchBody)?;
|
||||||
|
for arm in match_body.children_of_kind(c.syntax, TreeKind::MatchArm) {
|
||||||
|
let arm = &c.syntax[arm];
|
||||||
|
|
||||||
|
// Evaluate pattern...
|
||||||
|
compile_pattern(c, arm.nth_tree(0)?)?;
|
||||||
|
|
||||||
|
// ...If false jump to next arm.
|
||||||
|
let jump_next_index = c.push(Instruction::JumpFalse(0));
|
||||||
|
|
||||||
|
// ...If true run expression and jump out.
|
||||||
|
compile_expression(c, arm.nth_tree(2)?);
|
||||||
|
patches.push(c.push(Instruction::Jump(0)));
|
||||||
|
|
||||||
|
c.patch(jump_next_index, |i| Instruction::JumpFalse(i));
|
||||||
|
}
|
||||||
|
c.push_panic("Fell through all match arms");
|
||||||
|
|
||||||
|
// Patch the jumps to the end of the match expression.
|
||||||
|
for patch in patches {
|
||||||
|
c.patch(patch, |i| Instruction::Jump(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
OK
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
|
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
|
||||||
compile_expression(c, tree.nth_tree(0)?);
|
compile_expression(c, tree.nth_tree(0)?);
|
||||||
|
|
||||||
|
|
@ -766,7 +813,7 @@ fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
c.push(inst_panic!("panic compiling type expression eq {:?}", tree));
|
c.push_panic(format!("panic compiling type expression eq {:?}", tree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -877,7 +924,7 @@ fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
// We pass in the arguments.... by... field order?
|
// We pass in the arguments.... by... field order?
|
||||||
let Type::Object(mid, ct, _) = c.semantics.type_of(t) else {
|
let Type::Object(mid, ct, _) = c.semantics.type_of(t) else {
|
||||||
c.push(inst_panic!("new obj not ob"));
|
c.push_panic("new obj not ob");
|
||||||
return OK;
|
return OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -963,7 +1010,7 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
class.static_env.clone()
|
class.static_env.clone()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
c.push(inst_panic!("cannot get environment of {typ}"));
|
c.push_panic("cannot get environment of {typ}");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1018,7 +1065,7 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
||||||
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
|
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
|
||||||
};
|
};
|
||||||
if matches!(cr, None) {
|
if matches!(cr, None) {
|
||||||
c.push(inst_panic!("stat {:?}", tree));
|
c.push_panic(format!("stat {:?}", tree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum VMErrorCode {
|
pub enum VMErrorCode {
|
||||||
#[error("code panic (syntax or semantic error)")]
|
#[error("code panic (syntax or semantic error): {0}")]
|
||||||
Panic,
|
Panic(Rc<str>),
|
||||||
#[error("internal error: stack underflow")]
|
#[error("internal error: stack underflow")]
|
||||||
StackUnderflow,
|
StackUnderflow,
|
||||||
#[error("internal error: stack type mismatch: {0:?} is not {1:?}")]
|
#[error("internal error: stack type mismatch: {0:?} is not {1:?}")]
|
||||||
|
|
@ -394,7 +394,12 @@ fn eval_one(
|
||||||
stack: &mut Vec<Frame>,
|
stack: &mut Vec<Frame>,
|
||||||
) -> Result<Flow> {
|
) -> Result<Flow> {
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::Panic => return Err(VMErrorCode::Panic),
|
Instruction::Panic(index) => {
|
||||||
|
let v = f
|
||||||
|
.get_string(index)
|
||||||
|
.unwrap_or_else(|_| "!!panic string out of range!!".into());
|
||||||
|
return Err(VMErrorCode::Panic(v));
|
||||||
|
}
|
||||||
Instruction::BoolNot => {
|
Instruction::BoolNot => {
|
||||||
let value = f.pop_bool()?;
|
let value = f.pop_bool()?;
|
||||||
f.push_bool(!value);
|
f.push_bool(!value);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64)
|
||||||
// `and` that follows the declaration in the `is` still has the variables
|
// `and` that follows the declaration in the `is` still has the variables
|
||||||
// from the `is` binding in scope.
|
// from the `is` binding in scope.
|
||||||
if weapon is MeleeWeapon and distance > 1 or
|
if weapon is MeleeWeapon and distance > 1 or
|
||||||
weapon is w : RangedWeapon and (distance < w.minRange or distance > w.maxRange) {
|
weapon is w:RangedWeapon and (distance < w.minRange or distance > w.maxRange) {
|
||||||
print("You are out of range");
|
print("You are out of range");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +127,12 @@ fun test() -> f64 {
|
||||||
sum = sum + v;
|
sum = sum + v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let it = new Iterator { current: 0 };
|
||||||
|
sum = sum + match it.next() {
|
||||||
|
v:f64 -> 100,
|
||||||
|
_ -> 1000,
|
||||||
|
};
|
||||||
|
|
||||||
// Unroll by hand...
|
// Unroll by hand...
|
||||||
let it = new Iterator { current: 0 };
|
let it = new Iterator { current: 0 };
|
||||||
while true {
|
while true {
|
||||||
|
|
@ -141,5 +147,6 @@ fun test() -> f64 {
|
||||||
// like the above.
|
// like the above.
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ignore never finished compiling `match`
|
// @ignore not finished yet, still compiler bugs
|
||||||
// @no-errors
|
// @no-errors
|
||||||
|
// @eval: Float(90.0)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue