Browse Source

Add math operations

github-actions
Garrit Franke 2 years ago
parent
commit
e22f5647c6
  1. 10
      examples/hello_world.sb
  2. 10
      examples_out/out.js
  3. 26
      src/generator/js.rs
  4. 8
      src/lexer/mod.rs
  5. 46
      src/parser/mod.rs
  6. 61
      src/parser/node_type.rs
  7. 65
      src/parser/tests.rs

10
examples/hello_world.sb

@ -1,9 +1,7 @@
// main.sb
fn main() {
return foo(2);
}
fn foo(x) {
return x;
return 2 * fib(1);
}
fn fib(n) {
return 2 + 1;
}

10
examples_out/out.js

@ -1,8 +1,8 @@
// out.js
function main() {
return foo(2);
return 2 * fib(1)
}
function foo(x) {
return x;
function fib(n) {
return 2 + 1
}
console.log(main());
console.log(main())

26
src/generator/js.rs

@ -55,6 +55,7 @@ fn generate_expression(expr: Expression) -> String {
Expression::Char(_) => todo!(),
Expression::FunctionCall(name, e) => generate_function_call(name, e),
Expression::Assign(_, _) => todo!(),
Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right),
}
}
@ -67,6 +68,7 @@ fn generate_function_call(func: String, args: Vec<Expression>) -> String {
Expression::FunctionCall(n, a) => generate_function_call(n, a),
Expression::Str(s) | Expression::Variable(s) => s,
Expression::Assign(_, _) => todo!(),
Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right),
})
.collect::<Vec<String>>()
.join(",");
@ -79,3 +81,27 @@ fn generate_return(ret: Option<Expression>) -> String {
None => "return;\n".to_string(),
}
}
fn generate_bin_op(left: Expression, op: BinOp, right: Expression) -> String {
let op_str = match op {
BinOp::Addition => "+",
BinOp::And => "&&",
BinOp::Division => "/",
BinOp::Equal => "===",
BinOp::GreaterThan => ">",
BinOp::GreaterThanOrEqual => ">=",
BinOp::LessThan => "<",
BinOp::LessThanOrEqual => "<=",
BinOp::Modulus => "%",
BinOp::Multiplication => "*",
BinOp::NotEqual => "!==",
BinOp::Or => "||",
BinOp::Subtraction => "-",
};
format!(
"{l} {op} {r}",
l = generate_expression(left),
op = op_str,
r = generate_expression(right)
)
}

8
src/lexer/mod.rs

@ -62,9 +62,9 @@ pub enum TokenKind {
/// "=="
Equals,
/// "<"
SmallerThen,
LessThan,
/// ">"
LargerThen,
GreaterThan,
/// "("
BraceOpen,
/// ")"
@ -173,8 +173,8 @@ impl Cursor<'_> {
':' => Colon,
';' => SemiColon,
',' => Comma,
'<' => SmallerThen,
'>' => LargerThen,
'<' => LessThan,
'>' => GreaterThan,
'(' => BraceOpen,
')' => BraceClose,
'[' => SquareBraceOpen,

46
src/parser/mod.rs

@ -3,6 +3,7 @@ use crate::lexer::{Token, TokenKind, Value};
use crate::parser::node_type::Statement;
use crate::parser::node_type::*;
use crate::util::string_util::highlight_position_in_file;
use std::convert::TryFrom;
use std::iter::Peekable;
use std::vec::IntoIter;
@ -97,16 +98,17 @@ impl Parser {
)),
}
}
fn match_keyword(&mut self, keyword: Keyword) -> Result<(), String> {
let token = self.next_token();
match &token.kind {
TokenKind::Keyword(ref k) if k == &keyword => Ok(()),
_ => Err(self.make_error(TokenKind::SemiColon, token)),
}
}
fn match_operator(&mut self) -> Result<BinOp, String> {
let token = self.next_token();
BinOp::try_from(token.kind)
}
fn match_identifier(&mut self) -> Result<String, String> {
match self.next_token().kind {
TokenKind::Identifier(n) => Ok(n),
@ -272,18 +274,27 @@ impl Parser {
let token = self.next_token();
match token.kind {
TokenKind::Literal(Value::Int) => {
let state = Expression::Int(token.raw.parse::<u32>().map_err(|e| e.to_string())?);
let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?,
Err(_) => Expression::Int(token.raw.parse::<u32>().map_err(|e| e.to_string())?),
};
Ok(state)
}
TokenKind::Literal(Value::Str) => {
let state = Expression::Str(token.raw);
let state = match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?,
Err(_) => Expression::Str(token.raw),
};
Ok(state)
}
TokenKind::Identifier(val) => {
let next = self.peek().ok_or_else(|| "Token expected")?;
let state = match &next.kind {
TokenKind::BraceOpen => self.parse_function_call()?,
_ => Expression::Variable(val),
_ => match BinOp::try_from(self.peek().ok_or("Could not peek token")?.kind) {
Ok(_) => self.parse_bin_op()?,
Err(_) => Expression::Str(val),
},
};
Ok(state)
}
@ -291,6 +302,29 @@ impl Parser {
}
}
fn parse_bin_op(&mut self) -> Result<Expression, String> {
let left = self.prev().ok_or_else(|| "Expected Token")?;
match &left.kind {
TokenKind::Identifier(_) | TokenKind::Literal(_) => {
let op = self.match_operator()?;
let right = self.peek().ok_or_else(|| "Expected token")?;
match &right.kind {
TokenKind::Identifier(_) | TokenKind::Literal(_) => Ok(Expression::BinOp(
Box::from(Expression::try_from(left)?),
op,
Box::from(self.parse_expression()?),
)),
_ => Ok(Expression::BinOp(
Box::from(Expression::try_from(left)?),
op,
Box::from(self.parse_expression()?),
)),
}
}
_ => Err(self.make_error(TokenKind::Unknown, left)),
}
}
fn parse_declare(&mut self) -> Result<Statement, String> {
match (
self.next_token().kind,

61
src/parser/node_type.rs

@ -1,3 +1,6 @@
use crate::parser::{Token, TokenKind, Value};
use core::convert::TryFrom;
#[derive(Debug)]
pub struct Program {
pub func: Vec<Function>,
@ -33,4 +36,62 @@ pub enum Expression {
FunctionCall(String, Vec<Expression>),
Variable(String),
Assign(String, Box<Expression>),
BinOp(Box<Expression>, BinOp, Box<Expression>),
}
impl TryFrom<Token> for Expression {
type Error = String;
fn try_from(token: Token) -> std::result::Result<Self, String> {
let kind = token.kind;
match kind {
TokenKind::Identifier(val) => Ok(Expression::Variable(val)),
TokenKind::Literal(Value::Int) => Ok(Expression::Int(
token
.raw
.parse()
.map_err(|_| "Int value could not be parsed")?,
)),
TokenKind::Literal(Value::Str) => Ok(Expression::Str(token.raw)),
other => panic!("Value could not be parsed"),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum BinOp {
Addition,
Subtraction,
Multiplication,
Division,
Modulus,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
Equal,
NotEqual,
And,
Or,
}
impl TryFrom<TokenKind> for BinOp {
type Error = String;
fn try_from(token: TokenKind) -> Result<BinOp, String> {
match token {
TokenKind::Star => Ok(BinOp::Multiplication),
TokenKind::Slash => Ok(BinOp::Division),
TokenKind::Plus => Ok(BinOp::Addition),
TokenKind::Minus => Ok(BinOp::Subtraction),
TokenKind::LessThan => Ok(BinOp::LessThan),
TokenKind::GreaterThan => Ok(BinOp::GreaterThan),
TokenKind::Equals => Ok(BinOp::Equal),
// TokenKind::LessThanOrEqual => BinOp::LessThanOrEqual,
// TokenKind::GreaterThanOrEqual => BinOp::GreaterThanOrEqual,
// TokenKind::NotEquals => BinOp::NotEqual,
// TokenKind::And => BinOp::And,
// TokenKind::Or => BinOp::Or,
other => Err(format!("Token {:?} cannot be converted into a BinOp", other).into()),
}
}
}

65
src/parser/tests.rs

@ -149,3 +149,68 @@ fn test_parse_nexted_function_call() {
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_parse_basic_ops() {
let raw = "
fn main() {
return 2 * 5;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_parse_compound_ops() {
let raw = "
fn main() {
return 2 * 5 / 3;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
#[ignore]
fn test_parse_compound_ops_with_function_call() {
let raw = "
fn main() {
return 2 * fib(1) / 3;
}
fn fib(n) {
return n + 1;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_parse_compound_ops_with_strings() {
let raw = "
fn main() {
return 2 * \"Hello\";
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_parse_compound_ops_with_identifier() {
let raw = "
fn main(n) {
return 2 * n;
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}

Loading…
Cancel
Save