Skip to content

Commit

Permalink
feat: lexing and parsing let keyword for defining variables
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Russak committed Dec 10, 2023
1 parent 575e607 commit d58bdea
Show file tree
Hide file tree
Showing 20 changed files with 1,520 additions and 981 deletions.
83 changes: 83 additions & 0 deletions crates/compiler/src/code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use std::{fmt::{Display, Formatter}};

use lexer::PError;
use parser::{Node, Op, Value};
use vm::{Instr, Instrs, OpCode};
struct Code {
code: Vec<VInst>,
}

impl Code {
pub fn new() -> Code {
Code {
code: Vec::new(),
}
}
pub fn push(&mut self, inst: VInst) -> usize {
self.code.push(inst);
self.code.len() - 1
}
pub fn append(&mut self, code: Code) {
self.code.extend(code.code);
}
pub fn to_bytes(&self) -> Vec<u8> {
vec![]
}

pub fn size(&self) -> usize {
self.code.iter().map(|c| c.op_code.size()).sum()
}
}

enum VArg {
Reg(u8),
Rel(i32),
Abs(u32),
}

enum VState {
Incomplete,
Complete,
}

struct VInst {
state: VState,
label: String,
op_code: OpCode,
args: Vec<VArg>,
inst: Option<Instr>
}

impl VInst {
pub fn new(op_code: OpCode, args: Vec<VArg>) -> VInst {
VInst {
state: VState::Incomplete,
label: String::new(),
op_code,
args,
inst: None,
}
}
pub fn build(&mut self) {
self.inst = Some(
match self.op_code {
OpCode::Load => Instr::Load(self.args[0], self.args[1]),
_ => panic!("Unknown op code: {}", self.op_code)
}
);
self.state = VState::Complete;
}
}

#[cfg(test)]
mod compiler_code_tests {
use super::*;

#[test]
fn test_code() {
let mut code = Code::new();
code.push(VInst::new(OpCode::Load, vec![VArg::Reg(0), VArg::Abs(0)]));
assert!(code.size() == 4);
}
}

29 changes: 26 additions & 3 deletions crates/compiler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//mod code;
use std::{fmt::{Display, Formatter}};

use lexer::PError;
Expand Down Expand Up @@ -84,9 +85,11 @@ impl Stack {
}
}

pub struct StackLocation {
address: usize,
size: usize,
pub enum Addr {
Mem(usize),
MemPlaceholder(String),
Stack(usize),
StackPlaceholder(String),
}

pub struct Compiler {
Expand Down Expand Up @@ -155,6 +158,26 @@ impl Compiler {
code.append(else_body);
Ok(code)
},
Op::While => {
let mut code = Code::new();
let mut condition = self.compile_node(&node.children[0])?;
let body = self.compile_node(&node.children[1])?;
condition.push(Instr::Pop(1));
condition.push(Instr::Load0(0));
let beq = Instr::Beq(0, 1, body.size() as i16);
let jmp = Instr::Jmp(-(condition.size() as i32+ beq.size() as i32 + body.size() as i32));
code.append(condition);
code.push(beq);
code.append(body);
code.push(jmp);
Ok(code)
},
Op::Assign => {
let mut code = Code::new();
code.append(self.compile_node(node.right().unwrap())?);
code.push(Instr::Pop(1));
Ok(code)
},
Op::Paren => {
self.compile_node(node.left().unwrap())
},
Expand Down
3 changes: 3 additions & 0 deletions crates/interpreter/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ impl Context {
}
None
}
pub fn define_var(&mut self, name: &str) {
self.dict.insert(name.to_string(), VType::Undefined);
}
pub fn set_var(&mut self, name: &str, value: VType) {
self.dict.insert(name.to_string(), value);
}
Expand Down
7 changes: 7 additions & 0 deletions crates/interpreter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ pub fn compute(node: &Node, context: &mut Rc<Context>) -> Result<VType, PError>
//dict.insert(name.id.as_ref().unwrap().clone(), func);
Ok(VType::Ref(name.id.as_ref().unwrap().clone()))
},
Op::DefineVar => {
Rc::get_mut(context).unwrap().define_var(node.id.as_ref().unwrap());
if !node.children.is_empty() {
compute(node.children.get(0).unwrap(), context)?;
}
Ok(VType::Undefined)
},
Op::While => {
let mut last = VType::Undefined;
while context.get_var("!return").is_none() && compute(node.children.get(0).unwrap(), context)? != VType::Bool(false) {
Expand Down
6 changes: 5 additions & 1 deletion crates/lexer/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub enum Token {
Gt(Location),
Geq(Location),
Return(Location),
Let(Location),
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand Down Expand Up @@ -72,6 +73,7 @@ impl Display for Token {
Token::Gt(pos) => write!(f, "Gt {}", pos),
Token::Geq(pos) => write!(f, "Geq {}", pos),
Token::Return(pos) => write!(f, "Return {}", pos),
Token::Let(pos) => write!(f, "Let {}", pos),
}
}
}
Expand Down Expand Up @@ -112,6 +114,7 @@ impl Token {
Token::Gt(pos) => *pos,
Token::Geq(pos) => *pos,
Token::Return(pos) => *pos,
Token::Let(pos) => *pos,
}
}

Expand Down Expand Up @@ -139,7 +142,8 @@ impl Token {
| Token::While(..)
| Token::Loop(..)
| Token::Fn(..)
| Token::Return(..))
| Token::Return(..)
| Token::Let(..))
}

pub fn is_noun(&self) -> bool {
Expand Down
1 change: 1 addition & 0 deletions crates/lexer/src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl<'a> Tokenizer<'a> {
"while" => return Ok(Token::While(p.set_range(size))),
"if" => return Ok(Token::If(p.set_range(size))),
"fn" => return Ok(Token::Fn(p.set_range(size))),
"let" => return Ok(Token::Let(p.set_range(size))),
"else" => return Ok(Token::Else(p.set_range(size))),
"loop" => return Ok(Token::Loop(p.set_range(size))),
"break" => return Ok(Token::Break(p.set_range(size))),
Expand Down
41 changes: 41 additions & 0 deletions crates/parser/src/define.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::slice::Iter;
use lexer::{Token, PError};
use super::{Op, Expression, Node, Params};
use lexer::Location;
use crate::Parser;
use crate::{expect, accept};

pub struct Define;

impl Parser for Define {
fn consume(token: &Token, iter: &mut Iter<Token>) -> Result<(Node, Option<Token>), PError> {
let name = accept!(iter, Id);
let Token::Id(_loc, id) = name else {
panic!("Unexpected token");
};

let mut tree = Node::new(Op::DefineVar, token.get_location()).set_id(id.clone());

let Some(tok) = iter.next() else {
return Err(PError::new(Location::Eof, "Unexpected end of file"));
};

match tok {
Token::Assign(loc) => {
let mut assign = Node::new(Op::Assign, name.get_location());
assign.add(Node::new(Op::Variable, name.get_location()).set_id(id.to_string()));
let (exp, tok) = Expression::consume(token, iter)?;
expect!(tok.clone(), Semi);
assign.add(exp);
tree.add(assign);
Ok((tree, tok))
},
Token::Semi(loc) => {
Ok((tree, Some(tok.clone())))
},
_ => {
Err(PError::new(token.get_location(), "Unexpected token"))
}
}
}
}
26 changes: 26 additions & 0 deletions crates/parser/src/detail/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

#[macro_export]
macro_rules! accept {
( $iter:ident, $token:ident ) => {
{
let Some(token) = $iter.next() else {
return Err(PError::new(Location::Eof, "Unexpected end of file"));
};
if !matches!(token, Token::$token(..)) {
return Err(PError::new(token.get_location(), format!("Unexpected token: {}", token).as_str()))
}
token
}
};
}
#[macro_export]
macro_rules! expect {
( $ret:expr, $token:ident ) => {
let Some(token) = $ret else {
return Err(PError::new(Location::Eof, "Unexpected end of file"))
};
if !matches!(token, Token::$token(..)) {
return Err(PError::new(token.get_location(),format!("Unexpected token: {}", token).as_str()))
}
};
}
7 changes: 7 additions & 0 deletions crates/parser/src/detail/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod helpers;
mod node;
mod value;

pub use helpers::*;
pub use node::*;
pub use value::*;
16 changes: 13 additions & 3 deletions crates/parser/src/node.rs → crates/parser/src/detail/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum Op {
Call,
While,
DefineFunc,
DefineVar,
Return,
Leq,
Lt,
Expand All @@ -34,6 +35,7 @@ impl Op {
pub fn priority(&self) -> u32 {
match self {
Op::Scope => 0,
Op::DefineVar => 6,
Op::Return => 6,
Op::Branch => 6,
Op::Loop => 6,
Expand Down Expand Up @@ -88,6 +90,7 @@ impl Display for Op {
Op::While => write!(f, "while"),
Op::DefineFunc => write!(f, "Fn"),
Op::Return => write!(f, "return"),
Op::DefineVar => write!(f, "let"),
}
}
}
Expand Down Expand Up @@ -136,10 +139,11 @@ impl Node {
self
}
pub fn set_id(mut self, id: String) -> Self {
if Op::Variable != self.op {
if matches!(self.op, Op::Variable | Op::DefineVar) {
self.id = Some(id);
} else {
panic!("Cannot set id on non-var node");
}
self.id = Some(id);
self
}

Expand Down Expand Up @@ -170,7 +174,7 @@ impl Node {
pub fn add(&mut self, node: Node) {
//println!("self: {} << {}", self, node);
match self.op {
Op::Call => {
Op::Call | Op::DefineVar => {
self.children.insert(0, node);
}
Op::Scope | Op::Branch | Op::Args | Op::Not | Op::While | Op::DefineFunc | Op::Return => {
Expand Down Expand Up @@ -335,6 +339,12 @@ impl Display for Node {
}
if self.children.len() != 1 { write!(f,")")? };
},
Op::DefineVar => {
if self.children.len() < 1 {
return write!(f,"let {}",self.id.as_ref().unwrap() )
};
write!(f,"let {}; {}", self.id.as_ref().unwrap(), OptionalNode(self.children.get(0)))?;
},
_ => write!(f,"N/A")?,
}
Ok(())
Expand Down
File renamed without changes.
11 changes: 10 additions & 1 deletion crates/parser/src/expr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::slice::Iter;
use lexer::{Location,Token, PError};
use super::{Node, Op, Block, Branch, Call, Loop, Func};
use super::{Node, Op, Block, Branch, Call, Loop, Func, Define};
use crate::Parser;

enum ExpressionState {
Expand Down Expand Up @@ -100,6 +100,15 @@ impl Parser for Expression {
tree.add(ret);
return Ok((tree, tok));
},
Token::Let(..) => {
let (block, tok) = Define::consume(token, iter)?;
if let Some(Token::Semi(..)) = tok {
tree.add(block);
return Ok((tree, tok));
} else {
return Err(PError::new(Location::Eof, format!("Unexpected end of file, semicolon not found {}", token.get_location()).as_str()));
}
},
_ => {
return Err(PError::new(token.get_location(), format!("Unexpected token {}", token).as_str()));
}
Expand Down
Loading

0 comments on commit d58bdea

Please sign in to comment.