Skip to content

Commit

Permalink
Adding support for values and variables
Browse files Browse the repository at this point in the history
  • Loading branch information
patbuc committed Aug 26, 2024
1 parent 8d4967b commit 40d795c
Show file tree
Hide file tree
Showing 11 changed files with 377 additions and 18 deletions.
48 changes: 41 additions & 7 deletions src/compiler/parser/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,66 @@ use crate::vm::opcodes::OpCode;
use crate::vm::{Block, Value};

impl Parser {
fn current_block(&mut self) -> &mut Block {
fn current_block(&self) -> &Block {
self.blocks.last().unwrap()
}

fn current_block_mut(&mut self) -> &mut Block {
self.blocks.last_mut().unwrap()
}

pub fn emit_return(&mut self) {
self.emit_op_code(OpCode::Return);
}

pub fn emit_constant(&mut self, value: Value) {
pub fn add_constant(&mut self, value: Value) -> u32 {
self.current_block_mut().add_constant(value)
}

pub fn emit_constant(&mut self, value: Value) -> u32 {
let line = self.previous_token.line;
self.current_block_mut().write_constant(value, line)
}

pub fn emit_value(&mut self, name: String) -> u32 {
let line = self.previous_token.line;
self.current_block_mut().write_value(name, line)
}

pub fn emit_variable(&mut self, name: String) -> u32 {
let line = self.previous_token.line;
self.current_block().write_constant(value, line)
self.current_block_mut().write_variable(name, line)
}

pub fn emit_string(&mut self, value: Value) {
pub fn emit_string(&mut self, value: Value) -> u32 {
let line = self.previous_token.line;
self.current_block().write_string(value, line);
self.current_block_mut().write_string(value, line)
}

pub fn emit_op_code(&mut self, op_code: OpCode) {
let line = self.previous_token.line;
self.current_block().write_op_code(op_code, line);
self.current_block_mut().write_op_code(op_code, line);
}

pub fn is_value(&self, name: &str) -> bool {
self.current_block().is_value(name)
}

pub fn emit_u8(&mut self, value: u8) {
self.current_block_mut().write_u8(value);
}

pub fn emit_u16(&mut self, value: u16) {
self.current_block_mut().write_u16(value);
}

pub fn emit_u32(&mut self, value: u32) {
self.current_block_mut().write_u32(value);
}

pub fn emit_op_codes(&mut self, op_code1: OpCode, op_code2: OpCode) {
let line = self.previous_token.line;
let current_block: &mut Block = self.current_block();
let current_block: &mut Block = self.current_block_mut();
current_block.write_op_code(op_code1, line);
current_block.write_op_code(op_code2, line);
}
Expand Down
112 changes: 109 additions & 3 deletions src/compiler/parser/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,60 @@ impl Parser {

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
pub(in crate::compiler) fn declaration(&mut self) {
self.statement();
if self.match_token(TokenType::Val) {
self.val_declaration();
} else if self.match_token(TokenType::Var) {
self.var_declaration();
} else {
self.statement();
}

if self.panic_mode {
self.exit_panic_mode();
}
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
fn val_declaration(&mut self) {
let name = self.parse_value();

if self.match_token(TokenType::Equal) {
self.expression(false);
} else {
self.emit_op_code(OpCode::Nil);
}

self.consume_either(
TokenType::NewLine,
TokenType::Eof,
"Expecting '\\n' or '\\0' after value declaration.",
);

self.emit_value(name);
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
fn var_declaration(&mut self) {
let name = self.parse_value();

if self.match_token(TokenType::Equal) {
self.expression(false);
} else {
self.emit_op_code(OpCode::Nil);
}

self.consume_either(
TokenType::NewLine,
TokenType::Eof,
"Expecting '\\n' or '\\0' after value declaration.",
);

self.emit_variable(name);
}

fn parse_value(&mut self) -> String {
self.consume(TokenType::Identifier, "Expecting variable name.");
self.previous_token.token.clone()
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
Expand Down Expand Up @@ -94,8 +147,8 @@ impl Parser {

while precedence as u8
<= self
.get_rule(self.current_token.token_type.clone())
.precedence as u8
.get_rule(self.current_token.token_type.clone())
.precedence as u8
{
self.advance();
let infix_rule = self.get_rule(self.previous_token.token_type.clone()).infix;
Expand All @@ -109,6 +162,35 @@ impl Parser {
}
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
pub(super) fn variable(&mut self) {
let name = &*self.previous_token.token;
let is_value = self.is_value(name);
let index = self.add_constant(string!(name.to_string()));
if index <= 0xFF {
self.emit_op_code(if is_value {
OpCode::GetValue
} else {
OpCode::GetVariable
});
self.emit_u8(index as u8);
} else if index <= 0xFFFF {
self.emit_op_code(if is_value {
OpCode::GetValue2
} else {
OpCode::GetVariable2
});
self.emit_u16(index as u16);
} else {
self.emit_op_code(if is_value {
OpCode::GetValue4
} else {
OpCode::GetVariable4
});
self.emit_u32(index);
}
}

#[cfg_attr(feature = "disassemble", instrument(skip(self)))]
pub(super) fn number(&mut self) {
let value = f64::from_str(&*self.previous_token.token).unwrap();
Expand Down Expand Up @@ -264,4 +346,28 @@ impl Parser {
}
eprintln!(": {}", message);
}

fn exit_panic_mode(&mut self) {
self.panic_mode = false;
loop {
if self.previous_token.token_type == TokenType::NewLine
|| self.previous_token.token_type == TokenType::Eof
{
return;
}
match self.current_token.token_type {
TokenType::Class
| TokenType::Fn
| TokenType::Val
| TokenType::Var
| TokenType::For
| TokenType::If
| TokenType::While
| TokenType::Print
| TokenType::Return => return,
_ => {}
}
self.advance();
}
}
}
2 changes: 1 addition & 1 deletion src/compiler/parser/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ lazy_static! {
(TokenType::GreaterEqual, ParseRule::new(None, Some(Parser::binary), Precedence::Comparison)),
(TokenType::Less, ParseRule::new(None, Some(Parser::binary), Precedence::Comparison)),
(TokenType::LessEqual, ParseRule::new(None, Some(Parser::binary), Precedence::Comparison)),
(TokenType::Identifier, ParseRule::new(None, None, Precedence::None)),
(TokenType::Identifier, ParseRule::new(Some(Parser::variable), None, Precedence::None)),
(TokenType::String, ParseRule::new(Some(Parser::string), None, Precedence::None)),
(TokenType::InterpolatedString, ParseRule::new(None, None, Precedence::None)),
(TokenType::Number, ParseRule::new(Some(Parser::number), None, Precedence::None)),
Expand Down
11 changes: 9 additions & 2 deletions src/neon.n
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
print "Hello" + " " + "World!"
print 42 * 3.14
print "Hello" + " " + "World 🌍"
print 42 * 3.14
val x = 42.3
var y = 3.14
print x
print y
val z = "x + y"
print z
print x * y
56 changes: 53 additions & 3 deletions src/vm/block/block.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::vm::opcodes::OpCode;
use crate::vm::{Block, Constants, Line, Value};
use crate::vm::{Block, Constants, Line, Value, Variables};

impl Block {
pub(crate) fn new(name: &str) -> Self {
Block {
name: String::from(name),
constants: Constants::new(),
variables: Variables::new(),
strings: Constants::new(),
instructions: Vec::new(),
lines: Vec::new(),
Expand All @@ -14,13 +15,21 @@ impl Block {
}

impl Block {
pub(crate) fn is_value(&self, name: &str) -> bool {
self.variables.values.contains(&name.to_string())
}

pub(crate) fn write_op_code(&mut self, op_code: OpCode, line: u32) {
self.add_line(self.instructions.len(), line);
self.instructions.push(op_code as u8)
}

pub(crate) fn write_constant(&mut self, value: Value, line: u32) {
let constant_index = self.constants.write_value(value);
pub(crate) fn add_constant(&mut self, value: Value) -> u32 {
self.constants.write_value(value)
}

pub(crate) fn write_constant(&mut self, value: Value, line: u32) -> u32 {
let constant_index = self.add_constant(value);
if constant_index <= 0xFF {
self.write_op_code(OpCode::Constant, line);
self.write_u8(constant_index as u8)
Expand All @@ -31,6 +40,37 @@ impl Block {
self.write_op_code(OpCode::Constant4, line);
self.write_u32(constant_index)
}
constant_index
}

pub(crate) fn write_value(&mut self, name: String, line: u32) -> u32 {
let value_index = self.variables.write_value(name);
if value_index <= 0xFF {
self.write_op_code(OpCode::SetValue, line);
self.write_u8(value_index as u8)
} else if value_index <= 0xFFFF {
self.write_op_code(OpCode::SetValue2, line);
self.write_u16(value_index as u16)
} else {
self.write_op_code(OpCode::SetValue4, line);
self.write_u32(value_index)
}
value_index
}

pub(crate) fn write_variable(&mut self, name: String, line: u32) -> u32 {
let variable_index = self.variables.write_variable(name);
if variable_index <= 0xFF {
self.write_op_code(OpCode::SetVariable, line);
self.write_u8(variable_index as u8)
} else if variable_index <= 0xFFFF {
self.write_op_code(OpCode::SetVariable2, line);
self.write_u16(variable_index as u16)
} else {
self.write_op_code(OpCode::SetVariable4, line);
self.write_u32(variable_index)
}
variable_index
}

pub(crate) fn write_string(&mut self, value: Value, line: u32) -> u32 {
Expand Down Expand Up @@ -72,6 +112,16 @@ impl Block {
self.strings.read_value(index)
}

#[inline(always)]
pub(in crate::vm) fn read_value(&self, index: usize) -> String {
self.variables.values[index].clone()
}

#[inline(always)]
pub(in crate::vm) fn read_variable(&self, index: usize) -> String {
self.variables.variables[index].clone()
}

#[inline(always)]
pub(in crate::vm) fn read_u8(&self, offset: usize) -> u8 {
self.instructions[offset]
Expand Down
39 changes: 38 additions & 1 deletion src/vm/block/disassembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ impl Block {
OpCode::String4 => self.string_instruction(instruction, offset),
OpCode::Print => self.simple_instruction(OpCode::Print, offset),
OpCode::Pop => self.simple_instruction(OpCode::Pop, offset),
OpCode::SetValue => self.variable_instruction(OpCode::SetValue, offset),
OpCode::SetValue2 => self.variable_instruction(OpCode::SetValue2, offset),
OpCode::SetValue4 => self.variable_instruction(OpCode::SetValue4, offset),
OpCode::SetVariable => self.variable_instruction(OpCode::SetVariable, offset),
OpCode::SetVariable2 => self.variable_instruction(OpCode::SetVariable2, offset),
OpCode::SetVariable4 => self.variable_instruction(OpCode::SetVariable4, offset),
OpCode::GetValue => self.variable_instruction(OpCode::GetValue, offset),
OpCode::GetValue2 => self.variable_instruction(OpCode::GetValue2, offset),
OpCode::GetValue4 => self.variable_instruction(OpCode::GetValue4, offset),
OpCode::GetVariable => self.variable_instruction(OpCode::GetVariable, offset),
OpCode::GetVariable2 => self.variable_instruction(OpCode::GetVariable2, offset),
OpCode::GetVariable4 => self.variable_instruction(OpCode::GetVariable4, offset),
};
}

Expand All @@ -70,7 +82,32 @@ impl Block {

let (index, offset_shift) = get_constant_index(self, &op_code, offset + 1);
let constant = self.read_constant(index);
println!("{:?} {:02} '{}'", op_code, index, as_number!(constant));
println!("{:?} {:02} '{}'", op_code, index, constant.to_string());
offset + 1 + offset_shift
}

fn variable_instruction(&self, op_code: OpCode, offset: usize) -> usize {
fn get_variable_index(block: &Block, op_code: &OpCode, offset: usize) -> (usize, usize) {
match op_code {
OpCode::SetValue => (block.read_u8(offset) as usize, 1),
OpCode::SetValue2 => (block.read_u16(offset) as usize, 2),
OpCode::SetValue4 => (block.read_u32(offset) as usize, 4),
OpCode::SetVariable => (block.read_u8(offset) as usize, 1),
OpCode::SetVariable2 => (block.read_u16(offset) as usize, 2),
OpCode::SetVariable4 => (block.read_u32(offset) as usize, 4),
OpCode::GetValue => (block.read_u8(offset) as usize, 1),
OpCode::GetValue2 => (block.read_u16(offset) as usize, 2),
OpCode::GetValue4 => (block.read_u32(offset) as usize, 4),
OpCode::GetVariable => (block.read_u8(offset) as usize, 1),
OpCode::GetVariable2 => (block.read_u16(offset) as usize, 2),
OpCode::GetVariable4 => (block.read_u32(offset) as usize, 4),
_ => panic!("Invalid OpCode"),
}
}

let (index, offset_shift) = get_variable_index(self, &op_code, offset + 1);
let constant = self.read_constant(index);
println!("{:?} {:02} '{}'", op_code, index, constant.to_string());
offset + 1 + offset_shift
}

Expand Down
1 change: 1 addition & 0 deletions src/vm/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mod constants;

#[cfg(feature = "disassemble")]
mod disassembler;
mod variables;
Loading

0 comments on commit 40d795c

Please sign in to comment.