Add doubles.
This commit is contained in:
parent
7de866cf9d
commit
9df9edc508
@ -44,6 +44,9 @@ pub fn std_core_println(args: &[Value]) -> Result<Value, Box<dyn Error>> {
|
|||||||
Value::Int(i) => {
|
Value::Int(i) => {
|
||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
|
Value::Double(d) => {
|
||||||
|
println!("{}", d);
|
||||||
|
}
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
println!("{}", s);
|
println!("{}", s);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@ impl AddExpression {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(vec![Diagnostic::new(
|
Err(vec![Diagnostic::new(
|
||||||
&format!("Cannot add {} to {}", lhs_type_info, rhs_type_info),
|
&format!("Cannot add {} to {}", rhs_type_info, lhs_type_info),
|
||||||
self.source_range.start(),
|
self.source_range.start(),
|
||||||
self.source_range.end(),
|
self.source_range.end(),
|
||||||
)])
|
)])
|
||||||
|
|||||||
31
dmc-lib/src/ast/double_literal.rs
Normal file
31
dmc-lib/src/ast/double_literal.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
|
pub struct DoubleLiteral {
|
||||||
|
value: f64,
|
||||||
|
source_range: SourceRange,
|
||||||
|
type_info: &'static TypeInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DoubleLiteral {
|
||||||
|
pub fn new(value: f64, source_range: SourceRange) -> Self {
|
||||||
|
const TYPE_INFO: TypeInfo = TypeInfo::Double;
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
source_range,
|
||||||
|
type_info: &TYPE_INFO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> f64 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
&self.type_info
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
|
&self.source_range
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::ast::add_expression::AddExpression;
|
use crate::ast::add_expression::AddExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
|
use crate::ast::double_literal::DoubleLiteral;
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
@ -25,6 +26,7 @@ pub enum Expression {
|
|||||||
Call(Call),
|
Call(Call),
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
Integer(IntegerLiteral),
|
Integer(IntegerLiteral),
|
||||||
|
Double(DoubleLiteral),
|
||||||
String(StringLiteral),
|
String(StringLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ impl Expression {
|
|||||||
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
||||||
Expression::Integer(_) => Ok(()),
|
Expression::Integer(_) => Ok(()),
|
||||||
|
Expression::Double(_) => Ok(()),
|
||||||
Expression::String(_) => Ok(()),
|
Expression::String(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,6 +63,7 @@ impl Expression {
|
|||||||
Expression::Call(call) => call.check_name_usages(symbol_table),
|
Expression::Call(call) => call.check_name_usages(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
||||||
Expression::Integer(_) => Ok(()),
|
Expression::Integer(_) => Ok(()),
|
||||||
|
Expression::Double(_) => Ok(()),
|
||||||
Expression::String(_) => Ok(()),
|
Expression::String(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,6 +80,7 @@ impl Expression {
|
|||||||
Expression::Call(call) => call.type_check(symbol_table),
|
Expression::Call(call) => call.type_check(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.type_check(symbol_table),
|
Expression::Identifier(identifier) => identifier.type_check(symbol_table),
|
||||||
Expression::Integer(_) => Ok(()),
|
Expression::Integer(_) => Ok(()),
|
||||||
|
Expression::Double(_) => Ok(()),
|
||||||
Expression::String(_) => Ok(()),
|
Expression::String(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,6 +93,7 @@ impl Expression {
|
|||||||
Expression::Call(call) => call.return_type_info(),
|
Expression::Call(call) => call.return_type_info(),
|
||||||
Expression::Identifier(identifier) => identifier.type_info(),
|
Expression::Identifier(identifier) => identifier.type_info(),
|
||||||
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
||||||
|
Expression::Double(double_literal) => double_literal.type_info(),
|
||||||
Expression::String(string_literal) => string_literal.type_info(),
|
Expression::String(string_literal) => string_literal.type_info(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +106,7 @@ impl Expression {
|
|||||||
Expression::Call(call) => call.source_range(),
|
Expression::Call(call) => call.source_range(),
|
||||||
Expression::Identifier(identifier) => identifier.source_range(),
|
Expression::Identifier(identifier) => identifier.source_range(),
|
||||||
Expression::Integer(integer_literal) => integer_literal.source_range(),
|
Expression::Integer(integer_literal) => integer_literal.source_range(),
|
||||||
|
Expression::Double(double_literal) => double_literal.source_range(),
|
||||||
Expression::String(string_literal) => string_literal.source_range(),
|
Expression::String(string_literal) => string_literal.source_range(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,6 +141,9 @@ impl Expression {
|
|||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
Some(IrExpression::Int(integer_literal.value()))
|
Some(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
|
Expression::Double(double_literal) => {
|
||||||
|
Some(IrExpression::Double(double_literal.value()))
|
||||||
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
Some(IrExpression::String(string_literal.content().into()))
|
Some(IrExpression::String(string_literal.content().into()))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,6 +105,9 @@ impl LetStatement {
|
|||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
|
Expression::Double(double_literal) => {
|
||||||
|
IrOperation::Load(IrExpression::Double(double_literal.value()))
|
||||||
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
IrOperation::Load(IrExpression::String(string_literal.content().into()))
|
IrOperation::Load(IrExpression::String(string_literal.content().into()))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
pub mod add_expression;
|
pub mod add_expression;
|
||||||
pub mod call;
|
pub mod call;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
|
pub mod double_literal;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod expression_statement;
|
pub mod expression_statement;
|
||||||
pub mod extern_function;
|
pub mod extern_function;
|
||||||
|
|||||||
@ -17,6 +17,7 @@ pub enum IrExpression {
|
|||||||
Parameter(Rc<IrParameter>),
|
Parameter(Rc<IrParameter>),
|
||||||
Variable(Rc<RefCell<IrVariable>>),
|
Variable(Rc<RefCell<IrVariable>>),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ impl IrExpression {
|
|||||||
IrExpression::Parameter(ir_parameter) => ir_parameter.type_info().clone(),
|
IrExpression::Parameter(ir_parameter) => ir_parameter.type_info().clone(),
|
||||||
IrExpression::Variable(ir_variable) => ir_variable.borrow().type_info().clone(),
|
IrExpression::Variable(ir_variable) => ir_variable.borrow().type_info().clone(),
|
||||||
IrExpression::Int(_) => TypeInfo::Integer,
|
IrExpression::Int(_) => TypeInfo::Integer,
|
||||||
|
IrExpression::Double(_) => TypeInfo::Double,
|
||||||
IrExpression::String(_) => TypeInfo::String,
|
IrExpression::String(_) => TypeInfo::String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,6 +46,7 @@ impl IrExpression {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
IrExpression::Int(i) => MoveOperand::Int(*i),
|
IrExpression::Int(i) => MoveOperand::Int(*i),
|
||||||
|
IrExpression::Double(d) => MoveOperand::Double(*d),
|
||||||
IrExpression::String(s) => {
|
IrExpression::String(s) => {
|
||||||
let constant_name = constants_table.get_or_insert(s);
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
MoveOperand::String(constant_name)
|
MoveOperand::String(constant_name)
|
||||||
@ -65,6 +68,7 @@ impl IrExpression {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
IrExpression::Int(i) => PushOperand::Int(*i),
|
IrExpression::Int(i) => PushOperand::Int(*i),
|
||||||
|
IrExpression::Double(d) => PushOperand::Double(*d),
|
||||||
IrExpression::String(s) => {
|
IrExpression::String(s) => {
|
||||||
let constant_name = constants_table.get_or_insert(s);
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
PushOperand::String(constant_name)
|
PushOperand::String(constant_name)
|
||||||
@ -75,31 +79,34 @@ impl IrExpression {
|
|||||||
pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand {
|
pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand {
|
||||||
match self {
|
match self {
|
||||||
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||||
TypeInfo::Integer | TypeInfo::String => {
|
TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => {
|
||||||
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
}
|
}
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"Attempt to add non-integer/non-string (found: {})",
|
"Attempt to add non- integer/double/string (found: {})",
|
||||||
ir_parameter.type_info()
|
ir_parameter.type_info()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
||||||
TypeInfo::Integer | TypeInfo::String => match ir_variable.borrow().descriptor() {
|
TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => {
|
||||||
|
match ir_variable.borrow().descriptor() {
|
||||||
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||||
AddOperand::Location(Location::Register(
|
AddOperand::Location(Location::Register(
|
||||||
register_variable.assigned_register(),
|
register_variable.assigned_register(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
IrVariableDescriptor::Stack(stack_variable) => {
|
IrVariableDescriptor::Stack(stack_variable) => AddOperand::Location(
|
||||||
AddOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
Location::StackFrameOffset(stack_variable.offset()),
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"Attempt to add non-integer/non-string (found: {})",
|
"Attempt to add non-integer/non-string (found: {})",
|
||||||
ir_variable.borrow().type_info()
|
ir_variable.borrow().type_info()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
IrExpression::Int(i) => AddOperand::Int(*i),
|
IrExpression::Int(i) => AddOperand::Int(*i),
|
||||||
|
IrExpression::Double(d) => AddOperand::Double(*d),
|
||||||
IrExpression::String(s) => {
|
IrExpression::String(s) => {
|
||||||
let constant_name = constants_table.get_or_insert(s);
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
AddOperand::String(constant_name)
|
AddOperand::String(constant_name)
|
||||||
@ -110,16 +117,16 @@ impl IrExpression {
|
|||||||
pub fn subtract_operand(&self) -> SubtractOperand {
|
pub fn subtract_operand(&self) -> SubtractOperand {
|
||||||
match self {
|
match self {
|
||||||
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||||
TypeInfo::Integer => SubtractOperand::Location(Location::StackFrameOffset(
|
TypeInfo::Integer | TypeInfo::Double => SubtractOperand::Location(
|
||||||
ir_parameter.stack_offset(),
|
Location::StackFrameOffset(ir_parameter.stack_offset()),
|
||||||
)),
|
),
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"Attempt to subtract with non-integer type (found {})",
|
"Attempt to subtract with non-integer type (found {})",
|
||||||
ir_parameter.type_info()
|
ir_parameter.type_info()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
||||||
TypeInfo::Integer => match ir_variable.borrow().descriptor() {
|
TypeInfo::Integer | TypeInfo::Double => match ir_variable.borrow().descriptor() {
|
||||||
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||||
SubtractOperand::Location(Location::Register(
|
SubtractOperand::Location(Location::Register(
|
||||||
vr_variable.assigned_register(),
|
vr_variable.assigned_register(),
|
||||||
@ -135,6 +142,7 @@ impl IrExpression {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
IrExpression::Int(i) => SubtractOperand::Int(*i),
|
IrExpression::Int(i) => SubtractOperand::Int(*i),
|
||||||
|
IrExpression::Double(d) => SubtractOperand::Double(*d),
|
||||||
IrExpression::String(_) => {
|
IrExpression::String(_) => {
|
||||||
panic!("Attempt to subtract with a string");
|
panic!("Attempt to subtract with a string");
|
||||||
}
|
}
|
||||||
@ -157,6 +165,7 @@ impl IrExpression {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
IrExpression::Int(i) => ReturnOperand::Int(*i),
|
IrExpression::Int(i) => ReturnOperand::Int(*i),
|
||||||
|
IrExpression::Double(d) => ReturnOperand::Double(*d),
|
||||||
IrExpression::String(s) => {
|
IrExpression::String(s) => {
|
||||||
let constant_name = constants_table.get_or_insert(s);
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
ReturnOperand::String(constant_name)
|
ReturnOperand::String(constant_name)
|
||||||
@ -177,6 +186,9 @@ impl Display for IrExpression {
|
|||||||
IrExpression::Int(i) => {
|
IrExpression::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
IrExpression::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
IrExpression::String(s) => {
|
IrExpression::String(s) => {
|
||||||
write!(f, "\"{}\"", s)
|
write!(f, "\"{}\"", s)
|
||||||
}
|
}
|
||||||
@ -202,6 +214,7 @@ impl VrUser for IrExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrExpression::Int(_) => HashSet::new(),
|
IrExpression::Int(_) => HashSet::new(),
|
||||||
|
IrExpression::Double(_) => HashSet::new(),
|
||||||
IrExpression::String(_) => HashSet::new(),
|
IrExpression::String(_) => HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,6 +243,9 @@ impl VrUser for IrExpression {
|
|||||||
IrExpression::Int(_) => {
|
IrExpression::Int(_) => {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
IrExpression::Double(_) => {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
IrExpression::String(_) => {
|
IrExpression::String(_) => {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
@ -257,6 +273,9 @@ impl VrUser for IrExpression {
|
|||||||
IrExpression::Int(_) => {
|
IrExpression::Int(_) => {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
IrExpression::Double(_) => {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
IrExpression::String(_) => {
|
IrExpression::String(_) => {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,14 +59,37 @@ impl<'a> Lexer<'a> {
|
|||||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
||||||
// number literal
|
// number literal
|
||||||
let mut end = self.position;
|
let mut end = self.position;
|
||||||
for char in chunk.chars() {
|
let mut whole_chars = chunk.chars();
|
||||||
if char.is_ascii_digit() {
|
while let Some(c) = whole_chars.next() {
|
||||||
|
if c.is_ascii_digit() {
|
||||||
end += 1;
|
end += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut fraction_chars = chunk.chars().skip(end - self.position);
|
||||||
|
if fraction_chars.next().map(|c| c == '.').unwrap_or(false) {
|
||||||
|
let mut found_fraction = false;
|
||||||
|
while let Some(c) = fraction_chars.next() {
|
||||||
|
if c.is_ascii_digit() {
|
||||||
|
end += 1;
|
||||||
|
if !found_fraction {
|
||||||
|
end += 1; // to account for decimal point
|
||||||
|
found_fraction = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found_fraction {
|
||||||
|
Token::new(self.position, end, TokenKind::DoubleLiteral)
|
||||||
|
} else {
|
||||||
Token::new(self.position, end, TokenKind::IntegerLiteral)
|
Token::new(self.position, end, TokenKind::IntegerLiteral)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Token::new(self.position, end, TokenKind::IntegerLiteral)
|
||||||
|
}
|
||||||
} else if chunk.starts_with("\"") {
|
} else if chunk.starts_with("\"") {
|
||||||
// string literal
|
// string literal
|
||||||
let mut end = self.position;
|
let mut end = self.position;
|
||||||
@ -180,4 +203,40 @@ mod tests {
|
|||||||
let mut lexer = Lexer::new("extern");
|
let mut lexer = Lexer::new("extern");
|
||||||
assert_next(&mut lexer, TokenKind::Extern, 6);
|
assert_next(&mut lexer, TokenKind::Extern, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn double_literal() {
|
||||||
|
let mut lexer = Lexer::new("123.45");
|
||||||
|
assert_next(&mut lexer, TokenKind::DoubleLiteral, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_digit_whole_part_double() {
|
||||||
|
let mut lexer = Lexer::new("1.0");
|
||||||
|
assert_next(&mut lexer, TokenKind::DoubleLiteral, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_digits_fraction_double() {
|
||||||
|
let mut lexer = Lexer::new("1.23");
|
||||||
|
assert_next(&mut lexer, TokenKind::DoubleLiteral, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_literal() {
|
||||||
|
let mut lexer = Lexer::new("123");
|
||||||
|
assert_next(&mut lexer, TokenKind::IntegerLiteral, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doubles() {
|
||||||
|
let mut lexer = Lexer::new("println(1.23 + 2.34)");
|
||||||
|
assert_next(&mut lexer, TokenKind::Identifier, 7);
|
||||||
|
assert_next(&mut lexer, TokenKind::LeftParentheses, 1);
|
||||||
|
assert_next(&mut lexer, TokenKind::DoubleLiteral, 4);
|
||||||
|
assert_next(&mut lexer, TokenKind::Plus, 1);
|
||||||
|
assert_next(&mut lexer, TokenKind::DoubleLiteral, 4);
|
||||||
|
assert_next(&mut lexer, TokenKind::RightParentheses, 1);
|
||||||
|
assert!(lexer.next().is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::ast::add_expression::AddExpression;
|
use crate::ast::add_expression::AddExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
|
use crate::ast::double_literal::DoubleLiteral;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::expression_statement::ExpressionStatement;
|
use crate::ast::expression_statement::ExpressionStatement;
|
||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
@ -481,6 +482,15 @@ impl<'a> Parser<'a> {
|
|||||||
source_range,
|
source_range,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
TokenKind::DoubleLiteral => {
|
||||||
|
let raw = self.token_text(¤t);
|
||||||
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
|
self.advance();
|
||||||
|
Ok(Expression::Double(DoubleLiteral::new(
|
||||||
|
f64::from_str(raw).unwrap(),
|
||||||
|
source_range,
|
||||||
|
)))
|
||||||
|
}
|
||||||
TokenKind::String => {
|
TokenKind::String => {
|
||||||
let with_quotes = self.token_text(¤t);
|
let with_quotes = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
@ -509,7 +519,10 @@ impl<'a> Parser<'a> {
|
|||||||
if let Some(current) = &self.current {
|
if let Some(current) = &self.current {
|
||||||
if matches!(
|
if matches!(
|
||||||
current.kind(),
|
current.kind(),
|
||||||
TokenKind::IntegerLiteral | TokenKind::String | TokenKind::Identifier
|
TokenKind::IntegerLiteral
|
||||||
|
| TokenKind::DoubleLiteral
|
||||||
|
| TokenKind::String
|
||||||
|
| TokenKind::Identifier
|
||||||
) {
|
) {
|
||||||
arguments.append(&mut self.expression_list()?);
|
arguments.append(&mut self.expression_list()?);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ pub enum TokenKind {
|
|||||||
Let,
|
Let,
|
||||||
Equals,
|
Equals,
|
||||||
IntegerLiteral,
|
IntegerLiteral,
|
||||||
|
DoubleLiteral,
|
||||||
LongLiteral,
|
LongLiteral,
|
||||||
String,
|
String,
|
||||||
Extern,
|
Extern,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use std::rc::Rc;
|
|||||||
pub enum TypeInfo {
|
pub enum TypeInfo {
|
||||||
Any,
|
Any,
|
||||||
Integer,
|
Integer,
|
||||||
|
Double,
|
||||||
String,
|
String,
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<RefCell<FunctionSymbol>>),
|
||||||
Void,
|
Void,
|
||||||
@ -17,6 +18,7 @@ impl Display for TypeInfo {
|
|||||||
match self {
|
match self {
|
||||||
TypeInfo::Any => write!(f, "Any"),
|
TypeInfo::Any => write!(f, "Any"),
|
||||||
TypeInfo::Integer => write!(f, "Int"),
|
TypeInfo::Integer => write!(f, "Int"),
|
||||||
|
TypeInfo::Double => write!(f, "Double"),
|
||||||
TypeInfo::String => write!(f, "String"),
|
TypeInfo::String => write!(f, "String"),
|
||||||
TypeInfo::Function(function_symbol) => {
|
TypeInfo::Function(function_symbol) => {
|
||||||
write!(f, "fn(")?;
|
write!(f, "fn(")?;
|
||||||
@ -36,6 +38,7 @@ impl TypeInfo {
|
|||||||
match declared_name {
|
match declared_name {
|
||||||
"Any" => TypeInfo::Any,
|
"Any" => TypeInfo::Any,
|
||||||
"Int" => TypeInfo::Integer,
|
"Int" => TypeInfo::Integer,
|
||||||
|
"Double" => TypeInfo::Double,
|
||||||
"String" => TypeInfo::String,
|
"String" => TypeInfo::String,
|
||||||
"Void" => TypeInfo::Void,
|
"Void" => TypeInfo::Void,
|
||||||
_ => panic!("Unknown type: {}", declared_name),
|
_ => panic!("Unknown type: {}", declared_name),
|
||||||
@ -48,6 +51,9 @@ impl TypeInfo {
|
|||||||
TypeInfo::Integer => {
|
TypeInfo::Integer => {
|
||||||
matches!(other, TypeInfo::Integer)
|
matches!(other, TypeInfo::Integer)
|
||||||
}
|
}
|
||||||
|
TypeInfo::Double => {
|
||||||
|
matches!(other, TypeInfo::Double)
|
||||||
|
}
|
||||||
TypeInfo::String => {
|
TypeInfo::String => {
|
||||||
matches!(other, TypeInfo::String)
|
matches!(other, TypeInfo::String)
|
||||||
}
|
}
|
||||||
@ -62,8 +68,15 @@ impl TypeInfo {
|
|||||||
|
|
||||||
pub fn can_add(&self, rhs: &Self) -> bool {
|
pub fn can_add(&self, rhs: &Self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
TypeInfo::Integer => matches!(rhs, TypeInfo::Integer),
|
TypeInfo::Integer => {
|
||||||
TypeInfo::String => matches!(rhs, TypeInfo::String | TypeInfo::Integer),
|
matches!(rhs, TypeInfo::Integer | TypeInfo::Double | TypeInfo::String)
|
||||||
|
}
|
||||||
|
TypeInfo::Double => {
|
||||||
|
matches!(rhs, TypeInfo::Integer | TypeInfo::Double | TypeInfo::String)
|
||||||
|
}
|
||||||
|
TypeInfo::String => {
|
||||||
|
matches!(rhs, TypeInfo::Integer | TypeInfo::Double | TypeInfo::String)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,24 +85,41 @@ impl TypeInfo {
|
|||||||
match self {
|
match self {
|
||||||
TypeInfo::Integer => match rhs {
|
TypeInfo::Integer => match rhs {
|
||||||
TypeInfo::Integer => TypeInfo::Integer,
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
|
TypeInfo::Double => TypeInfo::Double,
|
||||||
TypeInfo::String => TypeInfo::String,
|
TypeInfo::String => TypeInfo::String,
|
||||||
_ => panic!(
|
_ => panic!("Unsupported add: {} + {}.", self, rhs),
|
||||||
"Adding things other than integers/strings to integer not yet supported."
|
},
|
||||||
),
|
TypeInfo::Double => match rhs {
|
||||||
|
TypeInfo::Integer | TypeInfo::Double => TypeInfo::Double,
|
||||||
|
TypeInfo::String => TypeInfo::String,
|
||||||
|
_ => panic!("Unsupported add: {} + {}.", self, rhs),
|
||||||
},
|
},
|
||||||
TypeInfo::String => TypeInfo::String,
|
TypeInfo::String => TypeInfo::String,
|
||||||
_ => panic!("Adding things other than integers and strings not yet supported"),
|
_ => panic!("Unsupported add: {} + {}.", self, rhs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_subtract(&self, rhs: &Self) -> bool {
|
pub fn can_subtract(&self, rhs: &Self) -> bool {
|
||||||
matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
|
match self {
|
||||||
|
TypeInfo::Integer => {
|
||||||
|
matches!(rhs, TypeInfo::Integer | TypeInfo::Double)
|
||||||
|
}
|
||||||
|
TypeInfo::Double => {
|
||||||
|
matches!(rhs, TypeInfo::Integer | TypeInfo::Double)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subtract_result(&self, rhs: &Self) -> TypeInfo {
|
pub fn subtract_result(&self, rhs: &Self) -> TypeInfo {
|
||||||
match self {
|
match self {
|
||||||
TypeInfo::Integer => match rhs {
|
TypeInfo::Integer => match rhs {
|
||||||
TypeInfo::Integer => TypeInfo::Integer,
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
|
TypeInfo::Double => TypeInfo::Double,
|
||||||
|
_ => panic!(),
|
||||||
|
},
|
||||||
|
TypeInfo::Double => match rhs {
|
||||||
|
TypeInfo::Integer | TypeInfo::Double => TypeInfo::Double,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
|
|||||||
@ -89,6 +89,7 @@ impl Display for Location {
|
|||||||
pub enum MoveOperand {
|
pub enum MoveOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +102,9 @@ impl Display for MoveOperand {
|
|||||||
MoveOperand::Int(i) => {
|
MoveOperand::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
MoveOperand::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
MoveOperand::String(s) => {
|
MoveOperand::String(s) => {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
@ -111,6 +115,7 @@ impl Display for MoveOperand {
|
|||||||
pub enum PushOperand {
|
pub enum PushOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +128,9 @@ impl Display for PushOperand {
|
|||||||
PushOperand::Int(i) => {
|
PushOperand::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
PushOperand::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
PushOperand::String(s) => {
|
PushOperand::String(s) => {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
@ -133,6 +141,7 @@ impl Display for PushOperand {
|
|||||||
pub enum AddOperand {
|
pub enum AddOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +154,9 @@ impl Display for AddOperand {
|
|||||||
AddOperand::Int(i) => {
|
AddOperand::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
AddOperand::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
AddOperand::String(s) => {
|
AddOperand::String(s) => {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
@ -155,6 +167,7 @@ impl Display for AddOperand {
|
|||||||
pub enum SubtractOperand {
|
pub enum SubtractOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SubtractOperand {
|
impl Display for SubtractOperand {
|
||||||
@ -166,6 +179,9 @@ impl Display for SubtractOperand {
|
|||||||
SubtractOperand::Int(i) => {
|
SubtractOperand::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
SubtractOperand::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,6 +189,7 @@ impl Display for SubtractOperand {
|
|||||||
pub enum ReturnOperand {
|
pub enum ReturnOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,6 +202,9 @@ impl Display for ReturnOperand {
|
|||||||
ReturnOperand::Int(i) => {
|
ReturnOperand::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
ReturnOperand::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
ReturnOperand::String(s) => {
|
ReturnOperand::String(s) => {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,30 @@
|
|||||||
use crate::instruction::SubtractOperand;
|
use crate::instruction::{AddOperand, SubtractOperand};
|
||||||
use crate::vm::CallFrame;
|
use crate::vm::CallFrame;
|
||||||
|
use crate::vm::constant::Constant;
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
use crate::vm::value_util::load_value;
|
use crate::vm::value_util::{load_constant_value, load_value};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn add_operand_to_value(
|
||||||
|
add_operand: &AddOperand,
|
||||||
|
registers: &[Value],
|
||||||
|
current_frame: &CallFrame,
|
||||||
|
constants: &HashMap<Rc<str>, Constant>,
|
||||||
|
) -> Value {
|
||||||
|
match add_operand {
|
||||||
|
AddOperand::Location(location) => load_value(
|
||||||
|
registers,
|
||||||
|
current_frame.stack(),
|
||||||
|
current_frame.fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
AddOperand::Int(i) => Value::Int(*i),
|
||||||
|
AddOperand::Double(d) => Value::Double(*d),
|
||||||
|
AddOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn subtract_operand_to_value(
|
pub fn subtract_operand_to_value(
|
||||||
subtract_operand: &SubtractOperand,
|
subtract_operand: &SubtractOperand,
|
||||||
@ -17,5 +40,6 @@ pub fn subtract_operand_to_value(
|
|||||||
)
|
)
|
||||||
.clone(),
|
.clone(),
|
||||||
SubtractOperand::Int(i) => Value::Int(*i),
|
SubtractOperand::Int(i) => Value::Int(*i),
|
||||||
|
SubtractOperand::Double(d) => Value::Double(*d),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use crate::instruction::{AddOperand, Instruction, MoveOperand, PushOperand, ReturnOperand};
|
use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand};
|
||||||
use crate::platform_function::PlatformFunction;
|
use crate::platform_function::PlatformFunction;
|
||||||
use crate::vm::constant::Constant;
|
use crate::vm::constant::Constant;
|
||||||
use crate::vm::function::Function;
|
use crate::vm::function::Function;
|
||||||
use crate::vm::instruction_helpers::subtract_operand_to_value;
|
use crate::vm::instruction_helpers::{add_operand_to_value, subtract_operand_to_value};
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
use crate::vm::value_util::*;
|
use crate::vm::value_util::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -226,6 +226,7 @@ pub fn call<'a>(
|
|||||||
)
|
)
|
||||||
.clone(),
|
.clone(),
|
||||||
MoveOperand::Int(i) => Value::Int(*i),
|
MoveOperand::Int(i) => Value::Int(*i),
|
||||||
|
MoveOperand::Double(d) => Value::Double(*d),
|
||||||
MoveOperand::String(constant_name) => {
|
MoveOperand::String(constant_name) => {
|
||||||
load_constant_value(context.constants(), constant_name)
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
@ -244,6 +245,7 @@ pub fn call<'a>(
|
|||||||
location,
|
location,
|
||||||
)
|
)
|
||||||
.clone(),
|
.clone(),
|
||||||
|
PushOperand::Double(d) => Value::Double(*d),
|
||||||
PushOperand::Int(i) => Value::Int(*i),
|
PushOperand::Int(i) => Value::Int(*i),
|
||||||
PushOperand::String(constant_name) => {
|
PushOperand::String(constant_name) => {
|
||||||
load_constant_value(context.constants(), constant_name)
|
load_constant_value(context.constants(), constant_name)
|
||||||
@ -316,86 +318,74 @@ pub fn call<'a>(
|
|||||||
|
|
||||||
/* Add instructions */
|
/* Add instructions */
|
||||||
Instruction::Add(left_operand, right_operand, destination) => {
|
Instruction::Add(left_operand, right_operand, destination) => {
|
||||||
let left_value = match left_operand {
|
let left_value = add_operand_to_value(
|
||||||
AddOperand::Location(location) => load_value(
|
&left_operand,
|
||||||
registers,
|
registers,
|
||||||
call_stack.top().stack(),
|
call_stack.top(),
|
||||||
call_stack.top().fp(),
|
context.constants(),
|
||||||
location,
|
);
|
||||||
)
|
|
||||||
.clone(),
|
let right_value = add_operand_to_value(
|
||||||
AddOperand::Int(i) => Value::Int(*i),
|
&right_operand,
|
||||||
AddOperand::String(constant_name) => {
|
registers,
|
||||||
load_constant_value(context.constants(), constant_name)
|
call_stack.top(),
|
||||||
}
|
context.constants(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = match left_value {
|
||||||
|
Value::Int(li) => match right_value {
|
||||||
|
Value::Int(ri) => Value::Int(li + ri),
|
||||||
|
Value::Double(rd) => Value::Double(li as f64 + rd),
|
||||||
|
Value::String(rs) => Value::String(format!("{}{}", li, rs).into()),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add non-addable {:?} type to {:?}",
|
||||||
|
right_value, left_value
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Value::Double(ld) => match right_value {
|
||||||
|
Value::Int(ri) => Value::Double(ld + ri as f64),
|
||||||
|
Value::Double(rd) => Value::Double(ld + rd),
|
||||||
|
Value::String(rs) => Value::String(format!("{}{}", ld, rs).into()),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add non-addable {:?} type to {:?}",
|
||||||
|
right_value, left_value
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Value::String(ref ls) => match right_value {
|
||||||
|
Value::Int(ri) => Value::String(format!("{}{}", ls, ri).into()),
|
||||||
|
Value::Double(rd) => Value::String(format!("{}{}", ls, rd).into()),
|
||||||
|
Value::String(rs) => Value::String(format!("{}{}", ls, rs).into()),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add non-addable {:?} type to {:?}",
|
||||||
|
right_value, left_value
|
||||||
|
),
|
||||||
|
},
|
||||||
|
_ => panic!("Attempt to add with non-addable type: {:?}", left_value),
|
||||||
};
|
};
|
||||||
|
|
||||||
let right_value = match right_operand {
|
put_value(registers, call_stack.top_mut(), destination, result);
|
||||||
AddOperand::Location(location) => load_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top().stack(),
|
|
||||||
call_stack.top().fp(),
|
|
||||||
location,
|
|
||||||
)
|
|
||||||
.clone(),
|
|
||||||
AddOperand::Int(i) => Value::Int(*i),
|
|
||||||
AddOperand::String(constant_name) => {
|
|
||||||
load_constant_value(context.constants(), constant_name)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Value::Int(left) = left_value {
|
|
||||||
if let Value::Int(right) = right_value {
|
|
||||||
let result = left + right;
|
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut(),
|
|
||||||
destination,
|
|
||||||
Value::Int(result),
|
|
||||||
);
|
|
||||||
} else if let Value::String(s) = right_value {
|
|
||||||
let result = format!("{}{}", left, s);
|
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut(),
|
|
||||||
destination,
|
|
||||||
Value::String(result.into()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
panic!("Attempt to add on non-addable type: {:?}", right_value);
|
|
||||||
}
|
|
||||||
} else if let Value::String(left) = left_value {
|
|
||||||
if let Value::Int(right) = right_value {
|
|
||||||
let result = format!("{}{}", left, right);
|
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut(),
|
|
||||||
destination,
|
|
||||||
Value::String(result.into()),
|
|
||||||
);
|
|
||||||
} else if let Value::String(right) = right_value {
|
|
||||||
let result = format!("{}{}", left, right);
|
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut(),
|
|
||||||
destination,
|
|
||||||
Value::String(result.into()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
panic!("Attempt to add on non-addable type: {:?}", right_value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("Attempt to add on non-addable type: {:?}", left_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Subtract(left_operand, right_operand, destination) => {
|
Instruction::Subtract(left_operand, right_operand, destination) => {
|
||||||
let left = subtract_operand_to_value(left_operand, registers, call_stack.top())
|
let left = subtract_operand_to_value(left_operand, registers, call_stack.top());
|
||||||
.unwrap_int();
|
let right = subtract_operand_to_value(right_operand, registers, call_stack.top());
|
||||||
let right = subtract_operand_to_value(right_operand, registers, call_stack.top())
|
|
||||||
.unwrap_int();
|
let result = match left {
|
||||||
let result = Value::Int(left - right);
|
Value::Int(li) => match right {
|
||||||
|
Value::Int(ri) => Value::Int(li - ri),
|
||||||
|
Value::Double(rd) => Value::Double(li as f64 - rd),
|
||||||
|
_ => panic!("Attempt to subtract {:?} from {:?}", right, left),
|
||||||
|
},
|
||||||
|
Value::Double(ld) => match right {
|
||||||
|
Value::Int(ri) => Value::Double(ld - ri as f64),
|
||||||
|
Value::Double(rd) => Value::Double(ld - rd),
|
||||||
|
_ => panic!("Attempt to subtract {:?} from {:?}", right, left),
|
||||||
|
},
|
||||||
|
_ => panic!("Attempt to subtract {:?} from {:?}", right, left),
|
||||||
|
};
|
||||||
|
|
||||||
put_value(registers, call_stack.top_mut(), destination, result);
|
put_value(registers, call_stack.top_mut(), destination, result);
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
@ -420,6 +410,7 @@ pub fn call<'a>(
|
|||||||
)
|
)
|
||||||
.clone(),
|
.clone(),
|
||||||
ReturnOperand::Int(i) => Value::Int(*i),
|
ReturnOperand::Int(i) => Value::Int(*i),
|
||||||
|
ReturnOperand::Double(d) => Value::Double(*d),
|
||||||
ReturnOperand::String(constant_name) => {
|
ReturnOperand::String(constant_name) => {
|
||||||
load_constant_value(context.constants(), constant_name)
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
Double(f64),
|
||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
Null,
|
Null,
|
||||||
}
|
}
|
||||||
@ -22,6 +23,13 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_double(&self) -> f64 {
|
||||||
|
match self {
|
||||||
|
Value::Double(d) => *d,
|
||||||
|
_ => panic!("Attempt to unwrap Double; found {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unwrap_string(&self) -> &Rc<str> {
|
pub fn unwrap_string(&self) -> &Rc<str> {
|
||||||
match self {
|
match self {
|
||||||
Value::String(s) => s,
|
Value::String(s) => s,
|
||||||
@ -36,6 +44,9 @@ impl Display for Value {
|
|||||||
Value::Int(i) => {
|
Value::Int(i) => {
|
||||||
write!(f, "{}", i)
|
write!(f, "{}", i)
|
||||||
}
|
}
|
||||||
|
Value::Double(d) => {
|
||||||
|
write!(f, "{}", d)
|
||||||
|
}
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ mod e2e_tests {
|
|||||||
panic!("There were diagnostics.");
|
panic!("There were diagnostics.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
fn prepare_context(input: &str) -> DvmContext {
|
||||||
let parse_result = parse_compilation_unit(input);
|
let parse_result = parse_compilation_unit(input);
|
||||||
let mut compilation_unit = match parse_result {
|
let mut compilation_unit = match parse_result {
|
||||||
Ok(compilation_unit) => compilation_unit,
|
Ok(compilation_unit) => compilation_unit,
|
||||||
@ -82,17 +82,29 @@ mod e2e_tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dvm_context
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_result(
|
||||||
|
dvm_context: &DvmContext,
|
||||||
|
function_name: &str,
|
||||||
|
arguments: &[Value],
|
||||||
|
) -> Option<Value> {
|
||||||
let mut registers: Vec<Value> = vec![Value::Null; REGISTER_COUNT];
|
let mut registers: Vec<Value> = vec![Value::Null; REGISTER_COUNT];
|
||||||
let mut call_stack = CallStack::new();
|
let mut call_stack = CallStack::new();
|
||||||
|
|
||||||
let result = call(
|
call(
|
||||||
&dvm_context,
|
&dvm_context,
|
||||||
&mut registers,
|
&mut registers,
|
||||||
&mut call_stack,
|
&mut call_stack,
|
||||||
function_name,
|
function_name,
|
||||||
&arguments,
|
&arguments,
|
||||||
);
|
)
|
||||||
match result {
|
}
|
||||||
|
|
||||||
|
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
||||||
|
let context = prepare_context(input);
|
||||||
|
match get_result(&context, function_name, arguments) {
|
||||||
None => panic!("Call returned no value"),
|
None => panic!("Call returned no value"),
|
||||||
Some(result_value) => {
|
Some(result_value) => {
|
||||||
assert_eq!(result_value, expected_value);
|
assert_eq!(result_value, expected_value);
|
||||||
@ -136,6 +148,58 @@ mod e2e_tests {
|
|||||||
fn simple_subtract() {
|
fn simple_subtract() {
|
||||||
assert_result("fn sub() -> Int 3 - 2 end", "sub", &vec![], Value::Int(1))
|
assert_result("fn sub() -> Int 3 - 2 end", "sub", &vec![], Value::Int(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_two_doubles() {
|
||||||
|
assert_result(
|
||||||
|
"fn add(a: Double, b: Double) -> Double a + b end",
|
||||||
|
"add",
|
||||||
|
&vec![Value::Double(1.23), Value::Double(1.23)],
|
||||||
|
Value::Double(1.23 + 1.23),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_two_double_variables() {
|
||||||
|
assert_result(
|
||||||
|
"
|
||||||
|
fn add() -> Double
|
||||||
|
let a = 1.0
|
||||||
|
let b = 2.0
|
||||||
|
a + b
|
||||||
|
end
|
||||||
|
",
|
||||||
|
"add",
|
||||||
|
&vec![Value::Double(1.0), Value::Double(2.0)],
|
||||||
|
Value::Double(3.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtract_two_doubles() {
|
||||||
|
assert_result(
|
||||||
|
"fn subtract(a: Double, b: Double) -> Double a - b end",
|
||||||
|
"subtract",
|
||||||
|
&vec![Value::Double(3.0), Value::Double(2.0)],
|
||||||
|
Value::Double(1.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtract_two_double_variables() {
|
||||||
|
assert_result(
|
||||||
|
"
|
||||||
|
fn subtract() -> Double
|
||||||
|
let a = 3.0
|
||||||
|
let b = 2.0
|
||||||
|
a - b
|
||||||
|
end
|
||||||
|
",
|
||||||
|
"subtract",
|
||||||
|
&vec![],
|
||||||
|
Value::Double(1.0),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
9
examples/doubles.dm
Normal file
9
examples/doubles.dm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
println(1.23 + 2.34)
|
||||||
|
println(1 + 2.0)
|
||||||
|
println(2.0 + 1)
|
||||||
|
println("hello " + 2.34)
|
||||||
|
println(2.34 + " hello")
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user