Add initial interpreter functionality (missing vars and funcs)
This commit is contained in:
parent
8d856d0651
commit
520357d930
4 changed files with 254 additions and 1 deletions
|
@ -1,9 +1,27 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use interpreter::interpret;
|
||||||
|
use parser::parse;
|
||||||
|
use tokenizer::tokenize;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
|
mod interpreter;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod token;
|
mod token;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
mod value;
|
||||||
|
|
||||||
pub fn compile(code: &str) {
|
pub fn compile(code: &str) {
|
||||||
let tokens = tokenizer::tokenize(code);
|
let tokens = tokenizer::tokenize(code);
|
||||||
parser::parse(&tokens);
|
parser::parse(&tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_interpreter() {
|
||||||
|
let lines = io::stdin().lines();
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if let Ok(code) = line {
|
||||||
|
println!("{}", interpret(&parse(&tokenize(&code))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
74
src/compiler/interpreter.rs
Normal file
74
src/compiler/interpreter.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
use crate::compiler::{
|
||||||
|
ast::Expression::{self, *},
|
||||||
|
value::Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[expect(unused_variables)]
|
||||||
|
pub fn interpret(ast: &Expression) -> Value {
|
||||||
|
match ast {
|
||||||
|
EmptyLiteral(_) => Value::None(),
|
||||||
|
IntLiteral(_, val) => Value::Int(*val),
|
||||||
|
BoolLiteral(_, val) => Value::Bool(*val),
|
||||||
|
Identifier(_, _) => todo!(), // Variables are TODO
|
||||||
|
UnaryOp(_, op, expr) => match *op {
|
||||||
|
"-" => -interpret(expr),
|
||||||
|
"not" => !interpret(expr),
|
||||||
|
_ => panic!("Unrecognized unary op {}", op),
|
||||||
|
},
|
||||||
|
BinaryOp(_, left, op, right) => match *op {
|
||||||
|
"+" => interpret(left) + interpret(right),
|
||||||
|
"*" => interpret(left) * interpret(right),
|
||||||
|
"-" => interpret(left) - interpret(right),
|
||||||
|
"/" => interpret(left) / interpret(right),
|
||||||
|
"%" => interpret(left) % interpret(right),
|
||||||
|
"==" => Value::Bool(interpret(left) == interpret(right)),
|
||||||
|
"!=" => Value::Bool(interpret(left) != interpret(right)),
|
||||||
|
"<" => Value::Bool(interpret(left) < interpret(right)),
|
||||||
|
"<=" => Value::Bool(interpret(left) <= interpret(right)),
|
||||||
|
">" => Value::Bool(interpret(left) > interpret(right)),
|
||||||
|
">=" => Value::Bool(interpret(left) >= interpret(right)),
|
||||||
|
"and" => interpret(left).and(&interpret(right)),
|
||||||
|
"or" => interpret(left).or(&interpret(right)),
|
||||||
|
"=" => todo!(), // Variables are TODO
|
||||||
|
_ => panic!("Unrecognized binary op {}", op),
|
||||||
|
},
|
||||||
|
VarDeclaration(_, name, expr) => todo!(), // Variables are TODO
|
||||||
|
Conditional(_, condition_expr, then_expr, else_expr) => {
|
||||||
|
if let Value::Bool(condition) = interpret(condition_expr) {
|
||||||
|
if condition {
|
||||||
|
interpret(then_expr)
|
||||||
|
} else if let Some(expr) = else_expr {
|
||||||
|
interpret(expr)
|
||||||
|
} else {
|
||||||
|
Value::None()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Non-bool as if-then-else condition!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
While(_, condition, do_expr) => {
|
||||||
|
let mut val = Value::None();
|
||||||
|
loop {
|
||||||
|
let condition = interpret(condition);
|
||||||
|
if let Value::Bool(cond) = condition {
|
||||||
|
if cond {
|
||||||
|
val = interpret(do_expr);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Non-boon as while-do condition!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
FunCall(_, name, args) => todo!(), // Functions are TODO
|
||||||
|
Block(_, expressions) => {
|
||||||
|
let mut val = Value::None();
|
||||||
|
for expression in expressions {
|
||||||
|
val = interpret(expression);
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
151
src/compiler/value.rs
Normal file
151
src/compiler/value.rs
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(PartialEq, PartialOrd, Debug)]
|
||||||
|
pub enum Value {
|
||||||
|
Int(i64),
|
||||||
|
Bool(bool),
|
||||||
|
None(),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn and(&self, other: &Self) -> Self {
|
||||||
|
if let Value::Bool(val1) = self {
|
||||||
|
if let Value::Bool(val2) = other {
|
||||||
|
Value::Bool(*val1 && *val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply and to non-bools!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply and to non-bools!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or(&self, other: &Self) -> Self {
|
||||||
|
if let Value::Bool(val1) = self {
|
||||||
|
if let Value::Bool(val2) = other {
|
||||||
|
Value::Bool(*val1 || *val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply or to non-bools!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply or to non-bools!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Value {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Value::Int(val) => write!(f, "{}", val),
|
||||||
|
Value::Bool(val) => write!(f, "{}", val),
|
||||||
|
Value::None() => write!(f, "<Unit>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: Self) -> Self::Output {
|
||||||
|
if let Value::Int(val1) = self {
|
||||||
|
if let Value::Int(val2) = other {
|
||||||
|
Value::Int(val1 + val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply + to non-ints!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply + to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, other: Self) -> Self::Output {
|
||||||
|
if let Value::Int(val1) = self {
|
||||||
|
if let Value::Int(val2) = other {
|
||||||
|
Value::Int(val1 * val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply * to non-ints!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply * to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
|
if let Value::Int(val1) = self {
|
||||||
|
if let Value::Int(val2) = other {
|
||||||
|
Value::Int(val1 - val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply - to non-ints!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply - to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, other: Self) -> Self::Output {
|
||||||
|
if let Value::Int(val1) = self {
|
||||||
|
if let Value::Int(val2) = other {
|
||||||
|
Value::Int(val1 / val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply / to non-ints!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply / to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rem for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn rem(self, other: Self) -> Self::Output {
|
||||||
|
if let Value::Int(val1) = self {
|
||||||
|
if let Value::Int(val2) = other {
|
||||||
|
Value::Int(val1 % val2)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply % to non-ints!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply % to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
if let Value::Int(val) = self {
|
||||||
|
Value::Int(-val)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply - to non-ints!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for Value {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
if let Value::Bool(val) = self {
|
||||||
|
Value::Bool(!val)
|
||||||
|
} else {
|
||||||
|
panic!("Can't apply ! to non-bools!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/main.rs
12
src/main.rs
|
@ -1,6 +1,16 @@
|
||||||
|
use std::env;
|
||||||
|
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
server::start("::".parse().unwrap(), 3000);
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
if let Some(flag) = args.get(1) {
|
||||||
|
if flag == "-i" {
|
||||||
|
compiler::start_interpreter();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
server::start("::".parse().unwrap(), 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue