Add div/mod parsing
This commit is contained in:
parent
691c91504b
commit
b9459a19bb
@ -46,11 +46,16 @@ Currently missing big features (TODOs) are:
|
|||||||
- Loops
|
- Loops
|
||||||
- Debug Information (PARTIALLY DONE)
|
- Debug Information (PARTIALLY DONE)
|
||||||
- Ability to specify types in literals and variable definitions
|
- Ability to specify types in literals and variable definitions
|
||||||
|
- Intrinsic functions
|
||||||
|
- Not-Unary
|
||||||
|
|
||||||
Big features that I want later but are not necessary:
|
Big features that I want later but are not necessary:
|
||||||
- Associated functions
|
- Associated functions
|
||||||
- User-defined binary operations
|
- User-defined binary operations
|
||||||
- Asymmetric binary operations (e.g. string + u32)
|
- Asymmetric binary operations (e.g. string + u32)
|
||||||
|
- Error handling
|
||||||
|
- Lexing & parsing of whitespace and comments as well
|
||||||
|
- LSP implementation
|
||||||
|
|
||||||
Smaller features:
|
Smaller features:
|
||||||
- Hex-numbers
|
- Hex-numbers
|
||||||
|
6
examples/div_mod.reid
Normal file
6
examples/div_mod.reid
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
|
fn main() -> u16 {
|
||||||
|
|
||||||
|
return (50 / 5 + 52 % 5);
|
||||||
|
}
|
@ -81,6 +81,8 @@ pub enum BinaryOperator {
|
|||||||
Add,
|
Add,
|
||||||
Minus,
|
Minus,
|
||||||
Mult,
|
Mult,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
|
||||||
And,
|
And,
|
||||||
LT,
|
LT,
|
||||||
@ -95,9 +97,11 @@ impl BinaryOperator {
|
|||||||
pub fn get_precedence(&self) -> i8 {
|
pub fn get_precedence(&self) -> i8 {
|
||||||
use BinaryOperator::*;
|
use BinaryOperator::*;
|
||||||
match &self {
|
match &self {
|
||||||
|
Minus => 5,
|
||||||
Add => 10,
|
Add => 10,
|
||||||
Minus => 10,
|
Mult => 15,
|
||||||
Mult => 20,
|
Div => 20,
|
||||||
|
Mod => 20,
|
||||||
And => 100,
|
And => 100,
|
||||||
LT => 100,
|
LT => 100,
|
||||||
LE => 100,
|
LE => 100,
|
||||||
|
@ -350,6 +350,8 @@ impl Parse for BinaryOperator {
|
|||||||
(Some(Token::Plus), _) => BinaryOperator::Add,
|
(Some(Token::Plus), _) => BinaryOperator::Add,
|
||||||
(Some(Token::Minus), _) => BinaryOperator::Minus,
|
(Some(Token::Minus), _) => BinaryOperator::Minus,
|
||||||
(Some(Token::Star), _) => BinaryOperator::Mult,
|
(Some(Token::Star), _) => BinaryOperator::Mult,
|
||||||
|
(Some(Token::Slash), _) => BinaryOperator::Div,
|
||||||
|
(Some(Token::Percent), _) => BinaryOperator::Mod,
|
||||||
(_, _) => Err(stream.expected_err("expected operator")?)?,
|
(_, _) => Err(stream.expected_err("expected operator")?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -286,6 +286,8 @@ impl ast::BinaryOperator {
|
|||||||
ast::BinaryOperator::Minus => mir::BinaryOperator::Minus,
|
ast::BinaryOperator::Minus => mir::BinaryOperator::Minus,
|
||||||
ast::BinaryOperator::Mult => mir::BinaryOperator::Mult,
|
ast::BinaryOperator::Mult => mir::BinaryOperator::Mult,
|
||||||
ast::BinaryOperator::And => mir::BinaryOperator::And,
|
ast::BinaryOperator::And => mir::BinaryOperator::And,
|
||||||
|
ast::BinaryOperator::Div => mir::BinaryOperator::Div,
|
||||||
|
ast::BinaryOperator::Mod => mir::BinaryOperator::Mod,
|
||||||
ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT),
|
ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT),
|
||||||
ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE),
|
ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE),
|
||||||
ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT),
|
ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT),
|
||||||
|
@ -659,6 +659,14 @@ impl mir::Expression {
|
|||||||
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
|
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
|
||||||
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs),
|
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs),
|
||||||
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs),
|
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs),
|
||||||
|
(mir::BinaryOperator::Div, true, true) => todo!(),
|
||||||
|
(mir::BinaryOperator::Div, true, false) => todo!(),
|
||||||
|
(mir::BinaryOperator::Div, false, true) => todo!(),
|
||||||
|
(mir::BinaryOperator::Div, false, false) => todo!(),
|
||||||
|
(mir::BinaryOperator::Mod, true, true) => todo!(),
|
||||||
|
(mir::BinaryOperator::Mod, true, false) => todo!(),
|
||||||
|
(mir::BinaryOperator::Mod, false, true) => todo!(),
|
||||||
|
(mir::BinaryOperator::Mod, false, false) => todo!(),
|
||||||
};
|
};
|
||||||
Some(StackValue(
|
Some(StackValue(
|
||||||
StackValueKind::Immutable(scope.block.build(instr).unwrap()),
|
StackValueKind::Immutable(scope.block.build(instr).unwrap()),
|
||||||
|
@ -2,7 +2,7 @@ use std::{fmt::Debug, str::Chars};
|
|||||||
|
|
||||||
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)]
|
#[derive(Eq, PartialEq, Clone, PartialOrd, Ord)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
/// Values
|
/// Values
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
@ -56,6 +56,10 @@ pub enum Token {
|
|||||||
Star,
|
Star,
|
||||||
/// `-`
|
/// `-`
|
||||||
Minus,
|
Minus,
|
||||||
|
/// `/`
|
||||||
|
Slash,
|
||||||
|
/// `%`
|
||||||
|
Percent,
|
||||||
|
|
||||||
/// `>`
|
/// `>`
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
@ -83,6 +87,8 @@ pub enum Token {
|
|||||||
/// `.`
|
/// `.`
|
||||||
Dot,
|
Dot,
|
||||||
|
|
||||||
|
Unknown(char),
|
||||||
|
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +155,18 @@ impl ToString for Token {
|
|||||||
Token::Comma => String::from(','),
|
Token::Comma => String::from(','),
|
||||||
Token::Dot => String::from('.'),
|
Token::Dot => String::from('.'),
|
||||||
Token::Eof => String::new(),
|
Token::Eof => String::new(),
|
||||||
|
Token::Slash => String::from('/'),
|
||||||
|
Token::Percent => String::from('%'),
|
||||||
|
Token::Unknown(val) => val.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Token {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Unknown(value) => write!(f, "Unknown(\'{}\')", value.to_string()),
|
||||||
|
_ => write!(f, "{}", self.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +181,7 @@ pub struct FullToken {
|
|||||||
impl Debug for FullToken {
|
impl Debug for FullToken {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!(
|
||||||
"{:?} (Ln {}, Col {})",
|
"Token({:?}) (Ln {}, Col {})",
|
||||||
self.token, self.position.1, self.position.0
|
self.token, self.position.1, self.position.0
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -343,8 +361,10 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
'}' => Token::BraceClose,
|
'}' => Token::BraceClose,
|
||||||
',' => Token::Comma,
|
',' => Token::Comma,
|
||||||
'.' => Token::Dot,
|
'.' => Token::Dot,
|
||||||
// Invalid token
|
'/' => Token::Slash,
|
||||||
_ => Err(Error::InvalidToken(*character, cursor.position))?,
|
'%' => Token::Percent,
|
||||||
|
// Unknown token
|
||||||
|
value => Token::Unknown(*value),
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.push(FullToken {
|
tokens.push(FullToken {
|
||||||
|
@ -299,6 +299,8 @@ impl Display for BinaryOperator {
|
|||||||
BinaryOperator::Mult => write!(f, "*"),
|
BinaryOperator::Mult => write!(f, "*"),
|
||||||
BinaryOperator::And => write!(f, "&&"),
|
BinaryOperator::And => write!(f, "&&"),
|
||||||
BinaryOperator::Cmp(op) => Display::fmt(op, f),
|
BinaryOperator::Cmp(op) => Display::fmt(op, f),
|
||||||
|
BinaryOperator::Div => write!(f, "/"),
|
||||||
|
BinaryOperator::Mod => write!(f, "%"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,14 +104,20 @@ impl TypeKind {
|
|||||||
BinaryOperator::Mult => self.clone(),
|
BinaryOperator::Mult => self.clone(),
|
||||||
BinaryOperator::And => TypeKind::Bool,
|
BinaryOperator::And => TypeKind::Bool,
|
||||||
BinaryOperator::Cmp(_) => TypeKind::Bool,
|
BinaryOperator::Cmp(_) => TypeKind::Bool,
|
||||||
|
BinaryOperator::Div => self.clone(),
|
||||||
|
BinaryOperator::Mod => self.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reverse of binop_type, where the given hint is the known required output
|
||||||
|
/// type of the binop, and the output is the hint for the lhs/rhs type.
|
||||||
pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
||||||
match op {
|
match op {
|
||||||
BinaryOperator::Add | BinaryOperator::Minus | BinaryOperator::Mult => {
|
BinaryOperator::Add
|
||||||
Some(self.clone())
|
| BinaryOperator::Minus
|
||||||
}
|
| BinaryOperator::Mult
|
||||||
|
| BinaryOperator::Div
|
||||||
|
| BinaryOperator::Mod => Some(self.clone()),
|
||||||
BinaryOperator::And => None,
|
BinaryOperator::And => None,
|
||||||
BinaryOperator::Cmp(_) => None,
|
BinaryOperator::Cmp(_) => None,
|
||||||
}
|
}
|
||||||
@ -465,12 +471,16 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zero(&self) -> Option<bool> {
|
pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> {
|
||||||
Some(self.num_value()? == 0)
|
if let Some(val) = self.num_value()? {
|
||||||
|
Ok(Some(val == 0))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_value(&self) -> Option<i128> {
|
pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> {
|
||||||
match &self.0 {
|
Ok(match &self.0 {
|
||||||
ExprKind::Variable(_) => None,
|
ExprKind::Variable(_) => None,
|
||||||
ExprKind::Indexed(..) => None,
|
ExprKind::Indexed(..) => None,
|
||||||
ExprKind::Accessed(..) => None,
|
ExprKind::Accessed(..) => None,
|
||||||
@ -478,22 +488,46 @@ impl Expression {
|
|||||||
ExprKind::Struct(..) => None,
|
ExprKind::Struct(..) => None,
|
||||||
ExprKind::Literal(literal) => literal.num_value(),
|
ExprKind::Literal(literal) => literal.num_value(),
|
||||||
ExprKind::BinOp(op, lhs, rhs) => match op {
|
ExprKind::BinOp(op, lhs, rhs) => match op {
|
||||||
BinaryOperator::Add => Some(lhs.num_value()? + rhs.num_value()?),
|
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
|
||||||
BinaryOperator::Minus => Some(lhs.num_value()? - rhs.num_value()?),
|
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
|
||||||
BinaryOperator::Mult => Some(lhs.num_value()? * rhs.num_value()?),
|
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
|
||||||
BinaryOperator::And => None,
|
BinaryOperator::And => None,
|
||||||
BinaryOperator::Cmp(_) => None,
|
BinaryOperator::Cmp(_) => None,
|
||||||
|
BinaryOperator::Div => {
|
||||||
|
let rhs_value = rhs.num_value()?;
|
||||||
|
if rhs_value == Some(0) {
|
||||||
|
Err(ErrorKind::DivideZero)?
|
||||||
|
}
|
||||||
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b)
|
||||||
|
}
|
||||||
|
BinaryOperator::Mod => {
|
||||||
|
let rhs_value = rhs.num_value()?;
|
||||||
|
if rhs_value == Some(0) {
|
||||||
|
Err(ErrorKind::DivideZero)?
|
||||||
|
}
|
||||||
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ExprKind::FunctionCall(..) => None,
|
ExprKind::FunctionCall(..) => None,
|
||||||
ExprKind::If(_) => None,
|
ExprKind::If(_) => None,
|
||||||
ExprKind::Block(_) => None,
|
ExprKind::Block(_) => None,
|
||||||
ExprKind::Borrow(_, _) => None,
|
ExprKind::Borrow(_, _) => None,
|
||||||
ExprKind::Deref(_) => None,
|
ExprKind::Deref(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.num_value(),
|
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe<T>(lhs: Option<i128>, rhs: Option<i128>, fun: T) -> Option<i128>
|
||||||
|
where
|
||||||
|
T: FnOnce(i128, i128) -> i128,
|
||||||
|
{
|
||||||
|
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
|
||||||
|
Some(fun(lhs, rhs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
impl IfExpression {
|
impl IfExpression {
|
||||||
pub fn return_type(
|
pub fn return_type(
|
||||||
&self,
|
&self,
|
||||||
|
@ -218,6 +218,8 @@ pub enum BinaryOperator {
|
|||||||
Add,
|
Add,
|
||||||
Minus,
|
Minus,
|
||||||
Mult,
|
Mult,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
And,
|
And,
|
||||||
Cmp(CmpOperator),
|
Cmp(CmpOperator),
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,8 @@ pub enum ErrorKind {
|
|||||||
NegativeUnsignedValue(TypeKind),
|
NegativeUnsignedValue(TypeKind),
|
||||||
#[error("Cannot cast type {0} into type {1}!")]
|
#[error("Cannot cast type {0} into type {1}!")]
|
||||||
NotCastableTo(TypeKind, TypeKind),
|
NotCastableTo(TypeKind, TypeKind),
|
||||||
|
#[error("Cannot divide by zero")]
|
||||||
|
DivideZero,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Struct used to implement a type-checking pass that can be performed on the
|
/// Struct used to implement a type-checking pass that can be performed on the
|
||||||
@ -426,7 +428,7 @@ impl Expression {
|
|||||||
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
||||||
|
|
||||||
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
||||||
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value(), rhs.num_value()) {
|
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?) {
|
||||||
if lhs_val < rhs_val {
|
if lhs_val < rhs_val {
|
||||||
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ impl std::iter::Sum for TokenRange {
|
|||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Expected {} got \"{}\"", .0, .1.to_string())]
|
#[error("Expected {} got \"{:?}\"", .0, .1)]
|
||||||
Expected(String, Token, TokenRange),
|
Expected(String, Token, TokenRange),
|
||||||
#[error("Source file contains no tokens")]
|
#[error("Source file contains no tokens")]
|
||||||
FileEmpty,
|
FileEmpty,
|
||||||
|
@ -18,15 +18,15 @@ fn test(source: &str, name: &str) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static ARRAY: &str = include_str!("../../reid_src/array.reid");
|
pub static ARRAY: &str = include_str!("../../examples/array.reid");
|
||||||
pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid");
|
pub static FIBONACCI: &str = include_str!("../../examples/fibonacci.reid");
|
||||||
pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid");
|
pub static HELLO_WORLD: &str = include_str!("../../examples/hello_world.reid");
|
||||||
pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid");
|
pub static MUTABLE: &str = include_str!("../../examples/mutable.reid");
|
||||||
pub static STRINGS: &str = include_str!("../../reid_src/strings.reid");
|
pub static STRINGS: &str = include_str!("../../examples/strings.reid");
|
||||||
pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid");
|
pub static STRUCTS: &str = include_str!("../../examples/struct.reid");
|
||||||
pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid");
|
pub static ARRAY_STRUCTS: &str = include_str!("../../examples/array_structs.reid");
|
||||||
pub static BORROW: &str = include_str!("../../reid_src/borrow.reid");
|
pub static BORROW: &str = include_str!("../../examples/borrow.reid");
|
||||||
pub static ARITHMETIC: &str = include_str!("../../reid_src/arithmetic.reid");
|
pub static ARITHMETIC: &str = include_str!("../../examples/arithmetic.reid");
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_compiles_well() {
|
fn array_compiles_well() {
|
||||||
|
Loading…
Reference in New Issue
Block a user