Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions example/graph_dfs.rts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
let graph = {
A: ["B", "C"],
B: ["D"],
C: ["E"],
D: ["F"],
E: [],
F: []
};

let sizes = {A: 2, B: 1, C: 1, D: 1, E: 0, F: 0};

let visited = {
A: 0, B: 0, C: 0, D: 0, E: 0, F: 0
};

function dfs(graph, sizes, visited, node) {
if (visited[node] == 1) {
return 0;
}
visited[node] = 1;
print node;

let neighbors = graph[node];
let count = sizes[node];
for (let i = 0; i < count; i++) {
dfs(graph, sizes, visited, neighbors[i]);
}
return 0;
}

dfs(graph, sizes, visited, "A");
24 changes: 23 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::{cell::RefCell, rc::Rc};

#[derive(Debug)]
Expand Down Expand Up @@ -44,6 +45,11 @@ pub enum Statement {
index: Vec<Expression>,
value: Expression,
},
AssignmentProperty {
object: String,
property: Vec<String>,
value: Expression,
},
}

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -83,11 +89,27 @@ pub enum Expression {
array: Box<Expression>,
index: Box<Expression>,
},
ObjectLiteral(Vec<(String, Expression)>),
PropertyAccess {
object: Box<Expression>,
property: String,
},
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Number(i32),
String(String),
Array(Rc<RefCell<Vec<Value>>>),
Object(Rc<RefCell<HashMap<String, Value>>>),
}

impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(Value::Number(a), Value::Number(b)) => a.partial_cmp(b),
(Value::String(a), Value::String(b)) => a.partial_cmp(b),
_ => None,
}
}
}
30 changes: 30 additions & 0 deletions src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub enum Instruction {
CreateArray(usize),
LoadIndex,
StoreIndex,
CreateObject(usize),
LoadProperty,
StoreProperty,
}

fn compile_expr(instructions: &mut Vec<Instruction>, expr: &Expression) {
Expand Down Expand Up @@ -114,6 +117,19 @@ fn compile_expr(instructions: &mut Vec<Instruction>, expr: &Expression) {
compile_expr(instructions, index);
instructions.push(Instruction::LoadIndex);
}
Expression::ObjectLiteral(objs) => {
for obj in objs {
let (key, value) = obj;
instructions.push(Instruction::LoadConst(Value::String(key.to_owned())));
compile_expr(instructions, value);
}
instructions.push(Instruction::CreateObject(objs.len()));
}
Expression::PropertyAccess { object, property } => {
compile_expr(instructions, object);
instructions.push(Instruction::LoadConst(Value::String(property.to_owned())));
instructions.push(Instruction::LoadProperty);
}
}
}

Expand Down Expand Up @@ -271,6 +287,20 @@ pub fn compile_statements(
compile_expr(instructions, &value);
instructions.push(Instruction::StoreIndex);
}
Statement::AssignmentProperty {
object,
property,
value,
} => {
instructions.push(Instruction::LoadVar(object));
for prop in property {
instructions.push(Instruction::LoadConst(Value::String(prop.to_owned())));
instructions.push(Instruction::LoadProperty);
}
instructions.pop();
compile_expr(instructions, &value);
instructions.push(Instruction::StoreProperty);
}
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub enum Token {
Return,
SquareLeft,
SquareRight,
Dot,
Colon,
}

pub fn tokenize(input: &str) -> Vec<Token> {
Expand Down Expand Up @@ -221,11 +223,21 @@ pub fn tokenize(input: &str) -> Vec<Token> {
}
}

'a'..='z' | 'A'..='Z' => {
'.' => {
tokens.push(Token::Dot);
chars.next();
}

':' => {
tokens.push(Token::Colon);
chars.next();
}

'a'..='z' | 'A'..='Z' | '_' => {
let mut ident = String::new();

while let Some(&c) = chars.peek() {
if c.is_alphanumeric() {
if c.is_alphanumeric() || c == '_' {
ident.push(c);
chars.next();
} else {
Expand Down
182 changes: 134 additions & 48 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,63 @@ impl Parser {
self.parse_primary()
}

fn parse_array_assignment(&mut self, name: String) -> Statement {
let mut indices = Vec::new();
while Some(&Token::SquareLeft) == self.peek() {
self.advance();
indices.push(self.parse_first());
match self.advance() {
Some(Token::SquareRight) => {}
_ => panic!("Expected ']' after array index"),
}
}
match self.advance() {
Some(Token::Equals) => {}
_ => panic!("Expected '=' after array index"),
}
let value = self.parse_first();
match self.advance() {
Some(Token::Semicolon) => {}
_ => panic!("Expected ';' after array assignment"),
}
Statement::AssignmentIndex {
array: name,
index: indices,
value,
}
}

fn parse_obj_assignment(&mut self, name: String) -> Statement {
let mut properties = Vec::new();
while let Some(token) = self.peek() {
if *token != Token::Dot {
break;
}
self.advance();
let prop_name = match self.advance() {
Some(Token::Identifier(name)) => name.to_owned(),
_ => panic!("Expected identifier"),
};
properties.push(prop_name);
}

match self.advance() {
Some(Token::Equals) => {}
_ => panic!("Expected '=' after object property"),
}
let value = self.parse_first();
match self.advance() {
Some(Token::Semicolon) => {}
_ => panic!("Expected ';' after object assignment"),
}

Statement::AssignmentProperty {
object: name,
property: properties,
value,
}
}

fn parse_call(&mut self, name: String) -> Statement {
self.advance(); // consume the identifier
if let Some(Token::LeftParentheses) = self.peek() {
Expand All @@ -369,29 +426,9 @@ impl Parser {
}
Statement::Expression(call_expr)
} else if let Some(Token::SquareLeft) = self.peek() {
let mut indices = Vec::new();
while Some(&Token::SquareLeft) == self.peek() {
self.advance();
indices.push(self.parse_first());
match self.advance() {
Some(Token::SquareRight) => {}
_ => panic!("Expected ']' after array index"),
}
}
match self.advance() {
Some(Token::Equals) => {}
_ => panic!("Expected '=' after array index"),
}
let value = self.parse_first();
match self.advance() {
Some(Token::Semicolon) => {}
_ => panic!("Expected ';' after array assignment"),
}
Statement::AssignmentIndex {
array: name,
index: indices,
value,
}
self.parse_array_assignment(name)
} else if let Some(Token::Dot) = self.peek() {
self.parse_obj_assignment(name)
} else {
self.parse_assignment(name)
}
Expand Down Expand Up @@ -421,6 +458,60 @@ impl Parser {
Expression::Call { name, args }
}

fn parse_object(&mut self) -> Expression {
let mut properties = Vec::new();
while let Some(token) = self.peek() {
if *token == Token::RightBrace {
break;
}
let key = match self.advance() {
Some(Token::Identifier(name)) => name.to_owned(),
_ => panic!("Expected identifier"),
};
match self.advance() {
Some(Token::Colon) => {}
_ => panic!("Expected ':'"),
}
let value = self.parse_first();
properties.push((key, value));
if let Some(Token::Comma) = self.peek() {
self.advance();
}
}

match self.advance() {
Some(Token::RightBrace) => {}
_ => panic!("Expected '}}'"),
}

Expression::ObjectLiteral(properties)
}

fn parse_index_access(&mut self, array: Expression) -> Expression {
self.advance(); // consume '['
let index_expr = self.parse_first();
match self.advance() {
Some(Token::SquareRight) => {}
_ => panic!("Expected ']' after array index"),
}
Expression::Index {
array: Box::new(array),
index: Box::new(index_expr),
}
}

fn parse_property_access(&mut self, object: Expression) -> Expression {
self.advance(); // consume '.'
let prop_name = match self.advance() {
Some(Token::Identifier(name)) => name.to_owned(),
_ => panic!("Expected identifier after '.'"),
};
Expression::PropertyAccess {
object: Box::new(object),
property: prop_name,
}
}

fn parse_primary(&mut self) -> Expression {
match self.advance() {
Some(Token::LeftParentheses) => {
Expand All @@ -433,39 +524,34 @@ impl Parser {
}
Some(Token::Number(n)) => Expression::Number(*n),
Some(Token::Identifier(name)) => {
let name = name.clone();
// If followed by '(', it's a function call expression
if let Some(Token::LeftParentheses) = self.peek() {
self.parse_call_args(name)
} else if let Some(Token::SquareLeft) = self.peek() {
self.parse_index(name)
} else {
Expression::Identifier(name)
let mut expr = Expression::Identifier(name.clone());
loop {
match self.peek() {
Some(Token::LeftParentheses) => {
let name = match expr {
Expression::Identifier(ref n) => n.clone(),
_ => panic!("Expected function name before '('"),
};
expr = self.parse_call_args(name);
}
Some(Token::SquareLeft) => {
expr = self.parse_index_access(expr);
}
Some(Token::Dot) => {
expr = self.parse_property_access(expr);
}
_ => break,
}
}
expr
}
Some(Token::SquareLeft) => self.parse_array_literal(),
Some(Token::LeftBrace) => self.parse_object(),
Some(Token::String(s)) => Expression::String(s.clone()),
_ => panic!("Invalid expression"),
}
}

fn parse_index(&mut self, array_name: String) -> Expression {
let mut result = Expression::Identifier(array_name.clone());
while Some(&Token::SquareLeft) == self.peek() {
self.advance(); // consume '['
let index_expr = self.parse_first();
match self.advance() {
Some(Token::SquareRight) => {}
_ => panic!("Expected ']' after array index"),
}
result = Expression::Index {
array: Box::new(result),
index: Box::new(index_expr),
};
}
result
}

fn parse_array_literal(&mut self) -> Expression {
let mut elements = Vec::new();
while let Some(token) = self.peek() {
Expand Down
Loading
Loading