Autoformat
This commit is contained in:
parent
f6152670aa
commit
588b3b5b2c
@ -1,6 +1,10 @@
|
|||||||
use std::{collections::HashMap, fmt::Display, rc::Rc};
|
use std::{collections::HashMap, fmt::Display, rc::Rc};
|
||||||
|
|
||||||
use crate::{ast::{Expression, BinOpType, UnOpType, Ast, Statement, If}, parser::parse, lexer::lex};
|
use crate::{
|
||||||
|
ast::{Ast, BinOpType, Expression, If, Statement, UnOpType},
|
||||||
|
lexer::lex,
|
||||||
|
parser::parse,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
@ -61,7 +65,11 @@ impl Interpreter {
|
|||||||
print!("{}", result);
|
print!("{}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::If(If {condition, body_true, body_false}) => {
|
Statement::If(If {
|
||||||
|
condition,
|
||||||
|
body_true,
|
||||||
|
body_false,
|
||||||
|
}) => {
|
||||||
if matches!(self.resolve_expr(condition), Value::I64(0)) {
|
if matches!(self.resolve_expr(condition), Value::I64(0)) {
|
||||||
self.run(body_false);
|
self.run(body_false);
|
||||||
} else {
|
} else {
|
||||||
@ -69,7 +77,6 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,9 +123,9 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhs = self.resolve_expr(lhs);
|
let lhs = self.resolve_expr(lhs);
|
||||||
|
|
||||||
match (lhs, rhs) {
|
match (lhs, rhs) {
|
||||||
@ -158,11 +165,10 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{Interpreter, Value};
|
use super::{Interpreter, Value};
|
||||||
use crate::ast::{Expression, BinOpType};
|
use crate::ast::{BinOpType, Expression};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interpreter_expr() {
|
fn test_interpreter_expr() {
|
||||||
@ -173,7 +179,12 @@ mod test {
|
|||||||
Expression::BinOp(
|
Expression::BinOp(
|
||||||
BinOpType::Add,
|
BinOpType::Add,
|
||||||
Expression::I64(1).into(),
|
Expression::I64(1).into(),
|
||||||
Expression::BinOp(BinOpType::Mul, Expression::I64(2).into(), Expression::I64(3).into()).into(),
|
Expression::BinOp(
|
||||||
|
BinOpType::Mul,
|
||||||
|
Expression::I64(2).into(),
|
||||||
|
Expression::I64(3).into(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
Expression::I64(4).into(),
|
Expression::I64(4).into(),
|
||||||
|
|||||||
@ -126,7 +126,7 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lex multiple characters as a number until encountering a non numeric digit. This includes
|
/// Lex multiple characters as a number until encountering a non numeric digit. This includes
|
||||||
/// the first character
|
/// the first character
|
||||||
fn lex_number(&mut self, first_char: char) -> Result<Token, LexErr> {
|
fn lex_number(&mut self, first_char: char) -> Result<Token, LexErr> {
|
||||||
// String representation of the integer value
|
// String representation of the integer value
|
||||||
let mut sval = String::from(first_char);
|
let mut sval = String::from(first_char);
|
||||||
|
|||||||
12
src/main.rs
12
src/main.rs
@ -1,8 +1,11 @@
|
|||||||
use std::{env::args, fs, io::{stdout, Write, stdin}};
|
use std::{
|
||||||
|
env::args,
|
||||||
|
fs,
|
||||||
|
io::{stdin, stdout, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use nek_lang::interpreter::Interpreter;
|
use nek_lang::interpreter::Interpreter;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct CliConfig {
|
struct CliConfig {
|
||||||
print_tokens: bool,
|
print_tokens: bool,
|
||||||
@ -12,7 +15,6 @@ struct CliConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
let mut conf = CliConfig::default();
|
let mut conf = CliConfig::default();
|
||||||
|
|
||||||
// Go through all commandline arguments except the first (filename)
|
// Go through all commandline arguments except the first (filename)
|
||||||
@ -42,14 +44,12 @@ fn main() {
|
|||||||
|
|
||||||
code.clear();
|
code.clear();
|
||||||
stdin().read_line(&mut code).unwrap();
|
stdin().read_line(&mut code).unwrap();
|
||||||
|
|
||||||
if code.trim() == "exit" {
|
if code.trim() == "exit" {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
interpreter.run_str(&code, conf.print_tokens, conf.print_ast);
|
interpreter.run_str(&code, conf.print_tokens, conf.print_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use crate::token::Token;
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
|
use crate::token::Token;
|
||||||
|
|
||||||
/// Parse the given tokens into an abstract syntax tree
|
/// Parse the given tokens into an abstract syntax tree
|
||||||
pub fn parse<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A) -> Ast {
|
pub fn parse<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A) -> Ast {
|
||||||
@ -20,7 +20,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
Self { tokens }
|
Self { tokens }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse tokens into an abstract syntax tree. This will continuously parse statements until
|
/// Parse tokens into an abstract syntax tree. This will continuously parse statements until
|
||||||
/// encountering end-of-file or a block end '}' .
|
/// encountering end-of-file or a block end '}' .
|
||||||
fn parse(&mut self) -> Ast {
|
fn parse(&mut self) -> Ast {
|
||||||
let mut prog = Vec::new();
|
let mut prog = Vec::new();
|
||||||
@ -30,23 +30,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
Token::Semicolon => {
|
Token::Semicolon => {
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
Token::EoF => break,
|
Token::EoF | Token::RBraces => break,
|
||||||
Token::RBraces => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default try to lex a statement
|
// By default try to lex a statement
|
||||||
_ => {
|
_ => prog.push(self.parse_stmt()),
|
||||||
prog.push(self.parse_stmt())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast { prog }
|
Ast { prog }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single statement from the tokens.
|
/// Parse a single statement from the tokens.
|
||||||
fn parse_stmt(&mut self) -> Statement {
|
fn parse_stmt(&mut self) -> Statement {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Token::Loop => Statement::Loop(self.parse_loop()),
|
Token::Loop => Statement::Loop(self.parse_loop()),
|
||||||
@ -108,13 +102,17 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body_false = self.parse();
|
body_false = self.parse();
|
||||||
|
|
||||||
if !matches!(self.next(), Token::RBraces) {
|
if !matches!(self.next(), Token::RBraces) {
|
||||||
panic!("Error lexing if: Expected '}}'")
|
panic!("Error lexing if: Expected '}}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
If { condition, body_true, body_false }
|
If {
|
||||||
|
condition,
|
||||||
|
body_true,
|
||||||
|
body_false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a loop statement from the tokens
|
/// Parse a loop statement from the tokens
|
||||||
@ -141,17 +139,20 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = self.parse();
|
body = self.parse();
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => panic!("Error lexing loop: Expected ';' or '{{'")
|
_ => panic!("Error lexing loop: Expected ';' or '{{'"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(self.next(), Token::RBraces) {
|
if !matches!(self.next(), Token::RBraces) {
|
||||||
panic!("Error lexing loop: Expected '}}'")
|
panic!("Error lexing loop: Expected '}}'")
|
||||||
}
|
}
|
||||||
|
|
||||||
Loop { condition, advancement, body }
|
Loop {
|
||||||
|
condition,
|
||||||
|
advancement,
|
||||||
|
body,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single expression from the tokens
|
/// Parse a single expression from the tokens
|
||||||
@ -222,7 +223,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
let operand = self.parse_primary();
|
let operand = self.parse_primary();
|
||||||
Expression::UnOp(UnOpType::BNot, operand.into())
|
Expression::UnOp(UnOpType::BNot, operand.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unary logical not
|
// Unary logical not
|
||||||
Token::LNot => {
|
Token::LNot => {
|
||||||
let operand = self.parse_primary();
|
let operand = self.parse_primary();
|
||||||
@ -246,8 +247,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{parse, Expression, BinOpType};
|
use super::{parse, BinOpType, Expression};
|
||||||
use crate::{token::Token, parser::{Statement, Ast}};
|
use crate::{
|
||||||
|
parser::{Ast, Statement},
|
||||||
|
token::Token,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
@ -269,13 +273,20 @@ mod tests {
|
|||||||
Expression::BinOp(
|
Expression::BinOp(
|
||||||
BinOpType::Add,
|
BinOpType::Add,
|
||||||
Expression::I64(1).into(),
|
Expression::I64(1).into(),
|
||||||
Expression::BinOp(BinOpType::Mul, Expression::I64(2).into(), Expression::I64(3).into()).into(),
|
Expression::BinOp(
|
||||||
|
BinOpType::Mul,
|
||||||
|
Expression::I64(2).into(),
|
||||||
|
Expression::I64(3).into(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
Expression::I64(4).into(),
|
Expression::I64(4).into(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = Ast { prog: vec![expected] };
|
let expected = Ast {
|
||||||
|
prog: vec![expected],
|
||||||
|
};
|
||||||
|
|
||||||
let actual = parse(tokens);
|
let actual = parse(tokens);
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user