[fine] While loops, nothing
This commit is contained in:
parent
1cc5ce6ca9
commit
ac3c158a81
7 changed files with 166 additions and 48 deletions
|
|
@ -15,18 +15,23 @@ pub enum Instruction {
|
||||||
|
|
||||||
BoolNot,
|
BoolNot,
|
||||||
Call(usize),
|
Call(usize),
|
||||||
CompareBool,
|
|
||||||
CompareFloat,
|
|
||||||
CompareString,
|
|
||||||
Discard,
|
Discard,
|
||||||
Dup,
|
Dup,
|
||||||
|
EqBool,
|
||||||
|
EqFloat,
|
||||||
|
EqString,
|
||||||
FloatAdd,
|
FloatAdd,
|
||||||
FloatDivide,
|
FloatDivide,
|
||||||
FloatMultiply,
|
FloatMultiply,
|
||||||
FloatSubtract,
|
FloatSubtract,
|
||||||
|
GreaterFloat,
|
||||||
|
GreaterString,
|
||||||
|
IsClass(i64),
|
||||||
Jump(usize),
|
Jump(usize),
|
||||||
JumpFalse(usize),
|
JumpFalse(usize),
|
||||||
JumpTrue(usize), // TODO: Only one of these, and use BoolNot?
|
JumpTrue(usize), // TODO: Only one of these, and use BoolNot?
|
||||||
|
LessFloat,
|
||||||
|
LessString,
|
||||||
LoadArgument(usize),
|
LoadArgument(usize),
|
||||||
LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index.
|
LoadExternFunction(usize), // NOTE: FUNKY, might want to indirect this index.
|
||||||
LoadFunction(usize),
|
LoadFunction(usize),
|
||||||
|
|
@ -36,6 +41,7 @@ pub enum Instruction {
|
||||||
NewObject(usize),
|
NewObject(usize),
|
||||||
PushFalse,
|
PushFalse,
|
||||||
PushFloat(f64),
|
PushFloat(f64),
|
||||||
|
PushInt(i64),
|
||||||
PushNothing,
|
PushNothing,
|
||||||
PushString(usize),
|
PushString(usize),
|
||||||
PushTrue,
|
PushTrue,
|
||||||
|
|
@ -44,9 +50,6 @@ pub enum Instruction {
|
||||||
StoreLocal(usize),
|
StoreLocal(usize),
|
||||||
StoreModule(usize),
|
StoreModule(usize),
|
||||||
StringAdd,
|
StringAdd,
|
||||||
|
|
||||||
IsClass(i64),
|
|
||||||
PushInt(i64),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Export {
|
pub enum Export {
|
||||||
|
|
@ -411,7 +414,8 @@ 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 {
|
||||||
match tr.nth_token(1)?.kind {
|
let op = tr.nth_token(1)?;
|
||||||
|
match op.kind {
|
||||||
TokenKind::Plus => compile_simple_binary_expression(c, tr, |_, t| match t {
|
TokenKind::Plus => compile_simple_binary_expression(c, tr, |_, t| match t {
|
||||||
Type::F64 => Instruction::FloatAdd,
|
Type::F64 => Instruction::FloatAdd,
|
||||||
Type::String => Instruction::StringAdd,
|
Type::String => Instruction::StringAdd,
|
||||||
|
|
@ -426,6 +430,36 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
TokenKind::Slash => {
|
TokenKind::Slash => {
|
||||||
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 {
|
||||||
|
Type::F64 => Instruction::LessFloat,
|
||||||
|
Type::String => Instruction::LessString,
|
||||||
|
_ => inst_panic!("panic less {}", t),
|
||||||
|
}),
|
||||||
|
TokenKind::LessEqual => {
|
||||||
|
compile_simple_binary_expression(c, tr, |_, t| match t {
|
||||||
|
Type::F64 => Instruction::GreaterFloat,
|
||||||
|
Type::String => Instruction::GreaterString,
|
||||||
|
_ => inst_panic!("panic less equal {}", t),
|
||||||
|
});
|
||||||
|
c.push(Instruction::BoolNot);
|
||||||
|
OK
|
||||||
|
}
|
||||||
|
TokenKind::Greater => compile_simple_binary_expression(c, tr, |_, t| match t {
|
||||||
|
Type::F64 => Instruction::GreaterFloat,
|
||||||
|
Type::String => Instruction::GreaterString,
|
||||||
|
_ => inst_panic!("panic greater {}", t),
|
||||||
|
}),
|
||||||
|
TokenKind::GreaterEqual => {
|
||||||
|
compile_simple_binary_expression(c, tr, |_, t| match t {
|
||||||
|
Type::F64 => Instruction::LessFloat,
|
||||||
|
Type::String => Instruction::LessString,
|
||||||
|
_ => inst_panic!("panic greater equal {}", t),
|
||||||
|
});
|
||||||
|
c.push(Instruction::BoolNot);
|
||||||
|
OK
|
||||||
|
}
|
||||||
|
|
||||||
TokenKind::And => {
|
TokenKind::And => {
|
||||||
// Compile the left hand side, it leaves a bool on the stack
|
// Compile the left hand side, it leaves a bool on the stack
|
||||||
compile_expression(c, tr.nth_tree(0)?);
|
compile_expression(c, tr.nth_tree(0)?);
|
||||||
|
|
@ -486,9 +520,9 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Instruction::PushTrue
|
Instruction::PushTrue
|
||||||
} else {
|
} else {
|
||||||
match arg_type {
|
match arg_type {
|
||||||
Type::F64 => Instruction::CompareFloat,
|
Type::F64 => Instruction::EqFloat,
|
||||||
Type::String => Instruction::CompareString,
|
Type::String => Instruction::EqString,
|
||||||
Type::Bool => Instruction::CompareBool, // ?
|
Type::Bool => Instruction::EqBool, // ?
|
||||||
_ => inst_panic!("panic comparing {}", arg_type),
|
_ => inst_panic!("panic comparing {}", arg_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -545,7 +579,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
}
|
}
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
_ => ice!(c, t, "Unsupported binary expression"),
|
_ => ice!(c, t, "Unsupported binary expression '{op}'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -898,13 +932,15 @@ fn compile_self_reference(c: &mut Compiler) -> CR {
|
||||||
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
|
||||||
let tree = &c.semantics.tree()[t];
|
let tree = &c.semantics.tree()[t];
|
||||||
let cr = match tree.kind {
|
let cr = match tree.kind {
|
||||||
TreeKind::FunctionDecl => compile_function_declaration(c, t, tree, gen_value),
|
|
||||||
TreeKind::ClassDecl => compile_class_declaration(c, t, tree, gen_value),
|
|
||||||
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
|
|
||||||
TreeKind::ExpressionStatement => compile_expression_statement(c, tree, gen_value),
|
|
||||||
TreeKind::IfStatement => compile_if_statement(c, tree, gen_value),
|
|
||||||
TreeKind::Block => compile_block_statement(c, t, gen_value),
|
TreeKind::Block => compile_block_statement(c, t, gen_value),
|
||||||
_ => ice!(c, t, "unsupported tree kind {:?}", tree.kind),
|
TreeKind::ClassDecl => compile_class_declaration(c, t, tree, gen_value),
|
||||||
|
TreeKind::ExpressionStatement => compile_expression_statement(c, tree, gen_value),
|
||||||
|
TreeKind::FunctionDecl => compile_function_declaration(c, t, tree, gen_value),
|
||||||
|
TreeKind::IfStatement => compile_if_statement(c, tree, gen_value),
|
||||||
|
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
|
||||||
|
TreeKind::WhileStatement => compile_while_statement(c, tree, gen_value),
|
||||||
|
|
||||||
|
_ => 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(inst_panic!("stat {:?}", tree));
|
||||||
|
|
@ -1076,3 +1112,20 @@ fn compile_block_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) -> CR
|
||||||
|
|
||||||
OK
|
OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_while_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
|
||||||
|
let start_index = c.function.instructions.len();
|
||||||
|
compile_expression(c, tree.nth_tree(1)?);
|
||||||
|
|
||||||
|
let jump_end_index = c.push(Instruction::JumpFalse(0));
|
||||||
|
|
||||||
|
compile_block_statement(c, tree.nth_tree(2)?, false);
|
||||||
|
c.push(Instruction::Jump(start_index));
|
||||||
|
|
||||||
|
c.patch(jump_end_index, |i| Instruction::JumpFalse(i));
|
||||||
|
if gen_value {
|
||||||
|
c.push(Instruction::PushNothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
OK
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,14 @@ pub enum TreeKind {
|
||||||
ListConstructor,
|
ListConstructor,
|
||||||
ListConstructorElement,
|
ListConstructorElement,
|
||||||
LiteralExpression,
|
LiteralExpression,
|
||||||
|
MatchArm,
|
||||||
|
MatchBody,
|
||||||
|
MatchExpression,
|
||||||
MemberAccess,
|
MemberAccess,
|
||||||
NewObjectExpression,
|
NewObjectExpression,
|
||||||
ParamList,
|
ParamList,
|
||||||
Parameter,
|
Parameter,
|
||||||
|
Pattern,
|
||||||
ReturnStatement,
|
ReturnStatement,
|
||||||
ReturnType,
|
ReturnType,
|
||||||
SelfParameter,
|
SelfParameter,
|
||||||
|
|
@ -156,13 +160,8 @@ pub enum TreeKind {
|
||||||
TypeParameter,
|
TypeParameter,
|
||||||
TypeParameterList,
|
TypeParameterList,
|
||||||
UnaryExpression,
|
UnaryExpression,
|
||||||
|
|
||||||
Pattern,
|
|
||||||
VariableBinding,
|
VariableBinding,
|
||||||
|
WhileStatement,
|
||||||
MatchExpression,
|
|
||||||
MatchBody,
|
|
||||||
MatchArm,
|
|
||||||
WildcardPattern,
|
WildcardPattern,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -781,6 +780,7 @@ const STATEMENT_RECOVERY: &[TokenKind] = &[
|
||||||
TokenKind::Return,
|
TokenKind::Return,
|
||||||
TokenKind::For,
|
TokenKind::For,
|
||||||
TokenKind::Class,
|
TokenKind::Class,
|
||||||
|
TokenKind::While,
|
||||||
];
|
];
|
||||||
|
|
||||||
fn block(p: &mut CParser) {
|
fn block(p: &mut CParser) {
|
||||||
|
|
@ -813,6 +813,8 @@ fn statement(p: &mut CParser) -> bool {
|
||||||
// require a semicolon at the end if it's all by itself.
|
// require a semicolon at the end if it's all by itself.
|
||||||
TokenKind::If => statement_if(p),
|
TokenKind::If => statement_if(p),
|
||||||
|
|
||||||
|
TokenKind::While => statement_while(p),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
if p.at(TokenKind::Semicolon) || p.at_any(EXPRESSION_FIRST) {
|
if p.at(TokenKind::Semicolon) || p.at_any(EXPRESSION_FIRST) {
|
||||||
statement_expression(p)
|
statement_expression(p)
|
||||||
|
|
@ -834,6 +836,24 @@ fn statement_if(p: &mut CParser) {
|
||||||
p.end(m, TreeKind::IfStatement);
|
p.end(m, TreeKind::IfStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn statement_while(p: &mut CParser) {
|
||||||
|
let m = p.start();
|
||||||
|
|
||||||
|
p.expect_start(TokenKind::While);
|
||||||
|
if p.at_any(EXPRESSION_FIRST) {
|
||||||
|
expression(p);
|
||||||
|
} else {
|
||||||
|
p.error("expected an expression for the loop condition");
|
||||||
|
}
|
||||||
|
if p.at(TokenKind::LeftBrace) {
|
||||||
|
block(p);
|
||||||
|
} else {
|
||||||
|
p.error("expected a block for the loop body");
|
||||||
|
}
|
||||||
|
|
||||||
|
p.end(m, TreeKind::WhileStatement);
|
||||||
|
}
|
||||||
|
|
||||||
fn statement_let(p: &mut CParser) {
|
fn statement_let(p: &mut CParser) {
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ impl fmt::Display for Type {
|
||||||
Error => write!(f, "<< INTERNAL ERROR >>"),
|
Error => write!(f, "<< INTERNAL ERROR >>"),
|
||||||
Unreachable => write!(f, "<< UNREACHABLE >>"),
|
Unreachable => write!(f, "<< UNREACHABLE >>"),
|
||||||
Assignment(_) => write!(f, "assignment"),
|
Assignment(_) => write!(f, "assignment"),
|
||||||
Nothing => write!(f, "()"),
|
Nothing => write!(f, "nothing"),
|
||||||
F64 => write!(f, "f64"),
|
F64 => write!(f, "f64"),
|
||||||
I64 => write!(f, "i64"),
|
I64 => write!(f, "i64"),
|
||||||
String => write!(f, "string"),
|
String => write!(f, "string"),
|
||||||
|
|
@ -1139,9 +1139,9 @@ impl<'a> Semantics<'a> {
|
||||||
TreeKind::Block => self.type_of_block(tree),
|
TreeKind::Block => self.type_of_block(tree),
|
||||||
TreeKind::CallExpression => self.type_of_call(tree),
|
TreeKind::CallExpression => self.type_of_call(tree),
|
||||||
TreeKind::ClassDecl => self.type_of_class_decl(t, tree),
|
TreeKind::ClassDecl => self.type_of_class_decl(t, tree),
|
||||||
TreeKind::FieldDecl => self.type_of_field_decl(tree),
|
|
||||||
TreeKind::ConditionalExpression => self.type_of_conditional(tree),
|
TreeKind::ConditionalExpression => self.type_of_conditional(tree),
|
||||||
TreeKind::ExpressionStatement => self.type_of_expression_statement(tree),
|
TreeKind::ExpressionStatement => self.type_of_expression_statement(tree),
|
||||||
|
TreeKind::FieldDecl => self.type_of_field_decl(tree),
|
||||||
TreeKind::FieldValue => self.type_of_field_value(t, tree),
|
TreeKind::FieldValue => self.type_of_field_value(t, tree),
|
||||||
TreeKind::ForStatement => Some(Type::Nothing),
|
TreeKind::ForStatement => Some(Type::Nothing),
|
||||||
TreeKind::FunctionDecl => self.type_of_function_decl(tree),
|
TreeKind::FunctionDecl => self.type_of_function_decl(tree),
|
||||||
|
|
@ -1153,6 +1153,9 @@ impl<'a> Semantics<'a> {
|
||||||
TreeKind::ListConstructor => self.type_of_list_constructor(t, tree),
|
TreeKind::ListConstructor => self.type_of_list_constructor(t, tree),
|
||||||
TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree),
|
TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree),
|
||||||
TreeKind::LiteralExpression => self.type_of_literal(tree),
|
TreeKind::LiteralExpression => self.type_of_literal(tree),
|
||||||
|
TreeKind::MatchArm => self.type_of_match_arm(tree),
|
||||||
|
TreeKind::MatchBody => self.type_of_match_body(tree),
|
||||||
|
TreeKind::MatchExpression => self.type_of_match_expression(tree),
|
||||||
TreeKind::MemberAccess => self.type_of_member_access(tree),
|
TreeKind::MemberAccess => self.type_of_member_access(tree),
|
||||||
TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree),
|
TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree),
|
||||||
TreeKind::Parameter => self.type_of_parameter(tree),
|
TreeKind::Parameter => self.type_of_parameter(tree),
|
||||||
|
|
@ -1164,10 +1167,7 @@ impl<'a> Semantics<'a> {
|
||||||
TreeKind::TypeIdentifier => self.type_of_type_identifier(t, tree),
|
TreeKind::TypeIdentifier => self.type_of_type_identifier(t, tree),
|
||||||
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
|
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
|
||||||
TreeKind::UnaryExpression => self.type_of_unary(tree),
|
TreeKind::UnaryExpression => self.type_of_unary(tree),
|
||||||
|
TreeKind::WhileStatement => Some(Type::Nothing),
|
||||||
TreeKind::MatchExpression => self.type_of_match_expression(tree),
|
|
||||||
TreeKind::MatchBody => self.type_of_match_body(tree),
|
|
||||||
TreeKind::MatchArm => self.type_of_match_arm(tree),
|
|
||||||
|
|
||||||
_ => self.internal_compiler_error(Some(t), "asking for a nonsense type"),
|
_ => self.internal_compiler_error(Some(t), "asking for a nonsense type"),
|
||||||
};
|
};
|
||||||
|
|
@ -1241,6 +1241,16 @@ impl<'a> Semantics<'a> {
|
||||||
(TokenKind::EqualEqual, Type::Bool, Type::Bool) => Some(Type::Bool),
|
(TokenKind::EqualEqual, Type::Bool, Type::Bool) => Some(Type::Bool),
|
||||||
(TokenKind::EqualEqual, Type::Nothing, Type::Nothing) => Some(Type::Bool),
|
(TokenKind::EqualEqual, Type::Nothing, Type::Nothing) => Some(Type::Bool),
|
||||||
|
|
||||||
|
(TokenKind::Less, Type::F64, Type::F64) => Some(Type::Bool),
|
||||||
|
(TokenKind::LessEqual, Type::F64, Type::F64) => Some(Type::Bool),
|
||||||
|
(TokenKind::Greater, Type::F64, Type::F64) => Some(Type::Bool),
|
||||||
|
(TokenKind::GreaterEqual, Type::F64, Type::F64) => Some(Type::Bool),
|
||||||
|
|
||||||
|
(TokenKind::Less, Type::String, Type::String) => Some(Type::Bool),
|
||||||
|
(TokenKind::LessEqual, Type::String, Type::String) => Some(Type::Bool),
|
||||||
|
(TokenKind::Greater, Type::String, Type::String) => Some(Type::Bool),
|
||||||
|
(TokenKind::GreaterEqual, Type::String, Type::String) => Some(Type::Bool),
|
||||||
|
|
||||||
// This is dumb and should be punished, probably.
|
// This is dumb and should be punished, probably.
|
||||||
(_, _, Type::Unreachable) => {
|
(_, _, Type::Unreachable) => {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
|
|
@ -1353,7 +1363,7 @@ impl<'a> Semantics<'a> {
|
||||||
"f64" => Some(Type::F64),
|
"f64" => Some(Type::F64),
|
||||||
"string" => Some(Type::String),
|
"string" => Some(Type::String),
|
||||||
"bool" => Some(Type::Bool),
|
"bool" => Some(Type::Bool),
|
||||||
"()" => Some(Type::Nothing),
|
"nothing" => Some(Type::Nothing),
|
||||||
"list" => {
|
"list" => {
|
||||||
let args =
|
let args =
|
||||||
tree.child_tree_of_kind(self.syntax_tree, TreeKind::TypeParameterList)?;
|
tree.child_tree_of_kind(self.syntax_tree, TreeKind::TypeParameterList)?;
|
||||||
|
|
@ -2041,6 +2051,8 @@ pub fn check(s: &Semantics) {
|
||||||
TreeKind::MatchArm => {}
|
TreeKind::MatchArm => {}
|
||||||
TreeKind::MatchBody => check_match_body(s, t, tree),
|
TreeKind::MatchBody => check_match_body(s, t, tree),
|
||||||
TreeKind::MatchExpression => {}
|
TreeKind::MatchExpression => {}
|
||||||
|
|
||||||
|
TreeKind::WhileStatement => check_while_statement(s, tree),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2240,6 +2252,7 @@ fn check_match_body(s: &Semantics, t: TreeRef, _tree: &Tree) {
|
||||||
let _ = s.type_of(t); // Checks arm count and compatibility.
|
let _ = s.type_of(t); // Checks arm count and compatibility.
|
||||||
|
|
||||||
// TODO: completeness checks
|
// TODO: completeness checks
|
||||||
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_pattern_analysis/usefulness/index.html
|
||||||
|
|
||||||
// let arms: Vec<_> = tree
|
// let arms: Vec<_> = tree
|
||||||
// .children_of_kind(s.syntax_tree, TreeKind::MatchArm)
|
// .children_of_kind(s.syntax_tree, TreeKind::MatchArm)
|
||||||
|
|
@ -2253,6 +2266,18 @@ fn check_match_body(s: &Semantics, t: TreeRef, _tree: &Tree) {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_while_statement(s: &Semantics, tree: &Tree) {
|
||||||
|
if let Some(expr) = tree.nth_tree(1) {
|
||||||
|
let expr_type = s.type_of(expr);
|
||||||
|
if !s.can_convert(&expr_type, &Type::Bool) {
|
||||||
|
s.report_error_tree_ref(
|
||||||
|
expr,
|
||||||
|
"the condition of the while loop must produce a boolean",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -430,21 +430,41 @@ fn eval_one(
|
||||||
|
|
||||||
f.push_string(new_string.into());
|
f.push_string(new_string.into());
|
||||||
}
|
}
|
||||||
Instruction::CompareBool => {
|
Instruction::EqBool => {
|
||||||
let x = f.pop_bool()?;
|
let x = f.pop_bool()?;
|
||||||
let y = f.pop_bool()?;
|
let y = f.pop_bool()?;
|
||||||
f.push_bool(x == y);
|
f.push_bool(x == y);
|
||||||
}
|
}
|
||||||
Instruction::CompareFloat => {
|
Instruction::EqFloat => {
|
||||||
let x = f.pop_float()?;
|
let x = f.pop_float()?;
|
||||||
let y = f.pop_float()?;
|
let y = f.pop_float()?;
|
||||||
f.push_bool(x == y);
|
f.push_bool(x == y);
|
||||||
}
|
}
|
||||||
Instruction::CompareString => {
|
Instruction::EqString => {
|
||||||
let x = f.pop_string()?;
|
let x = f.pop_string()?;
|
||||||
let y = f.pop_string()?;
|
let y = f.pop_string()?;
|
||||||
f.push_bool(x == y);
|
f.push_bool(x == y);
|
||||||
}
|
}
|
||||||
|
Instruction::GreaterFloat => {
|
||||||
|
let x = f.pop_float()?;
|
||||||
|
let y = f.pop_float()?;
|
||||||
|
f.push_bool(y > x);
|
||||||
|
}
|
||||||
|
Instruction::GreaterString => {
|
||||||
|
let x = f.pop_string()?;
|
||||||
|
let y = f.pop_string()?;
|
||||||
|
f.push_bool(y > x);
|
||||||
|
}
|
||||||
|
Instruction::LessFloat => {
|
||||||
|
let x = f.pop_float()?;
|
||||||
|
let y = f.pop_float()?;
|
||||||
|
f.push_bool(y < x);
|
||||||
|
}
|
||||||
|
Instruction::LessString => {
|
||||||
|
let x = f.pop_string()?;
|
||||||
|
let y = f.pop_string()?;
|
||||||
|
f.push_bool(y < x);
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::NewObject(slots) => {
|
Instruction::NewObject(slots) => {
|
||||||
let class_id = f.pop_int()?;
|
let class_id = f.pop_int()?;
|
||||||
|
|
@ -496,16 +516,16 @@ pub fn eval(
|
||||||
let instructions = f.func.instructions();
|
let instructions = f.func.instructions();
|
||||||
let instruction = instructions[index];
|
let instruction = instructions[index];
|
||||||
|
|
||||||
{
|
// {
|
||||||
eprint!("{index}: {instruction:?} [");
|
// eprint!("{index}: {instruction:?} [");
|
||||||
for val in f.stack.iter().rev().take(3) {
|
// for val in f.stack.iter().rev().take(3) {
|
||||||
eprint!("{val:?} ");
|
// eprint!("{val:?} ");
|
||||||
}
|
// }
|
||||||
if f.stack.len() > 3 {
|
// if f.stack.len() > 3 {
|
||||||
eprint!("...");
|
// eprint!("...");
|
||||||
}
|
// }
|
||||||
eprintln!("]");
|
// eprintln!("]");
|
||||||
}
|
// }
|
||||||
|
|
||||||
index += 1;
|
index += 1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64)
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun more_examples(weapon: MeleeWeapon or RangedWeapon) -> f64 or () {
|
fun more_examples(weapon: MeleeWeapon or RangedWeapon) -> f64 or nothing {
|
||||||
if weapon is w: RangedWeapon and w.maxRange > 10 {
|
if weapon is w: RangedWeapon and w.maxRange > 10 {
|
||||||
// w is still in scope here; the `and` is bound into a predicate expression
|
// w is still in scope here; the `and` is bound into a predicate expression
|
||||||
// and breaks exhaustivity
|
// and breaks exhaustivity
|
||||||
|
|
@ -115,7 +115,7 @@ fun test() -> f64 {
|
||||||
|
|
||||||
// Unroll by hand...
|
// Unroll by hand...
|
||||||
let it = new Iterator { current: 0 };
|
let it = new Iterator { current: 0 };
|
||||||
loop {
|
while true {
|
||||||
if it.next() is v: f64 {
|
if it.next() is v: f64 {
|
||||||
sum = sum + v;
|
sum = sum + v;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ fun test() {
|
||||||
// | 1: Return
|
// | 1: Return
|
||||||
// |
|
// |
|
||||||
// @eval: Nothing
|
// @eval: Nothing
|
||||||
// @type: 15 ()
|
// @type: 15 nothing
|
||||||
// @concrete:
|
// @concrete:
|
||||||
// | File
|
// | File
|
||||||
// | FunctionDecl
|
// | FunctionDecl
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if (if false { true }) { 32 } else { 23 }
|
if (if false { true }) { 32 } else { 23 }
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | 1:4: the type of the 'then' branch ('bool') must match the type of the 'else' branch ('()')
|
// | 1:4: the type of the 'then' branch ('bool') must match the type of the 'else' branch ('nothing')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue