import anthropic
import json
# Initialiser le client Anthropic
client = anthropic.Anthropic()
# Dictionnaire des catégories considérées comme dangereuses pour la modération de contenu, avec leurs définitions
unsafe_category_definitions = {
'Exploitation des enfants': 'Contenu qui représente la nudité d\'enfants ou qui permet, encourage, excuse ou représente l\'abus sexuel d\'enfants.',
'Théories du complot': """Contenu qui promeut ou approuve des théories non fondées, fausses ou trompeuses sur des événements, des situations ou des individus,
qui peuvent inciter à nuire ou miner la confiance du public dans les institutions ou les faits.""",
'Haine': """Contenu qui est haineux envers les personnes sur la base de leurs caractéristiques protégées
(race, couleur, ethnicité, origine nationale, handicap, affiliation religieuse, caste, orientation sexuelle, sexe, identité de genre et maladie grave),
ou contenu qui perpétue des stéréotypes négatifs.""",
'Armes à destruction massive': 'Contenu qui permet la création d\'armes de destruction massive.',
'Propriété intellectuelle': 'Contenu qui viole les droits de propriété intellectuelle de tiers.',
'Crimes non violents': 'Contenu qui permet, encourage ou excuse la commission de crimes non violents.',
'Vie privée': 'Contenu qui contient des informations sensibles et personnelles sur des individus privés.',
'Automutilation': 'Contenu qui permet, encourage ou excuse des actes d\'automut�# Shuumatsu/scarlet
# src/parser/parser.rs
use std::collections::HashMap;
use crate::ast::*;
use crate::lexer::*;
use crate::token::*;
#[derive(Debug, PartialEq, PartialOrd)]
enum Precedence {
Lowest,
Equals, // ==
LessGreater, // > or <
Sum, // +
Product, // *
Prefix, // -X or !X
Call, // myFunction(X)
Index, // array[index]
}
impl From<&Token> for Precedence {
fn from(token: &Token) -> Self {
match token {
Token::Equal | Token::NotEqual => Precedence::Equals,
Token::LessThan | Token::GreaterThan => Precedence::LessGreater,
Token::Plus | Token::Minus => Precedence::Sum,
Token::Slash | Token::Asterisk => Precedence::Product,
Token::LParen => Precedence::Call,
Token::LBracket => Precedence::Index,
_ => Precedence::Lowest,
}
}
}
type PrefixParseFn = fn(&mut Parser) -> Option<Expression>;
type InfixParseFn = fn(&mut Parser, Expression) -> Option<Expression>;
pub struct Parser {
lexer: Lexer,
curr_token: Token,
peek_token: Token,
errors: Vec<String>,
prefix_parse_fns: HashMap<Token, PrefixParseFn>,
infix_parse_fns: HashMap<Token, InfixParseFn>,
}
impl Parser {
pub fn new(lexer: Lexer) -> Self {
let mut parser = Parser {
lexer,
curr_token: Token::Illegal,
peek_token: Token::Illegal,
errors: Vec::new(),
prefix_parse_fns: HashMap::new(),
infix_parse_fns: HashMap::new(),
};
parser.register_prefix(Token::Ident("".to_string()), Parser::parse_identifier);
parser.register_prefix(Token::Int("".to_string()), Parser::parse_integer_literal);
parser.register_prefix(Token::Bang, Parser::parse_prefix_expression);
parser.register_prefix(Token::Minus, Parser::parse_prefix_expression);
parser.register_prefix(Token::True, Parser::parse_boolean);
parser.register_prefix(Token::False, Parser::parse_boolean);
parser.register_prefix(Token::LParen, Parser::parse_grouped_expression);
parser.register_prefix(Token::If, Parser::parse_if_expression);
parser.register_prefix(Token::Function, Parser::parse_function_literal);
parser.register_prefix(Token::String("".to_string()), Parser::parse_string_literal);
parser.register_prefix(Token::LBracket, Parser::parse_array_literal);
parser.register_prefix(Token::LBrace, Parser::parse_hash_literal);
parser.register_infix(Token::Plus, Parser::parse_infix_expression);
parser.register_infix(Token::Minus, Parser::parse_infix_expression);
parser.register_infix(Token::Slash, Parser::parse_infix_expression);
parser.register_infix(Token::Asterisk, Parser::parse_infix_expression);
parser.register_infix(Token::Equal, Parser::parse_infix_expression);
parser.register_infix(Token::NotEqual, Parser::parse_infix_expression);
parser.register_infix(Token::LessThan, Parser::parse_infix_expression);
parser.register_infix(Token::GreaterThan, Parser::parse_infix_expression);
parser.register_infix(Token::LParen, Parser::parse_call_expression);
parser.register_infix(Token::LBracket, Parser::parse_index_expression);
parser.next_token();
parser.next_token();
parser
}
fn register_prefix(&mut self, token: Token, func: PrefixParseFn) {
self.prefix_parse_fns.insert(token, func);
}
fn register_infix(&mut self, token: Token, func: InfixParseFn) {
self.infix_parse_fns.insert(token, func);
}
fn next_token(&mut self) {
self.curr_token = self.peek_token.clone();
self.peek_token = self.lexer.next_token();
}
pub fn parse_program(&mut self) -> Program {
let mut program = Program { statements: vec![] };
while !self.curr_token_is(Token::Eof) {
if let Some(stmt) = self.parse_statement() {
program.statements.push(stmt);
}
self.next_token();
}
program
}
fn parse_statement(&mut self) -> Option<Statement> {
match self.curr_token {
Token::Let => self.parse_let_statement(),
Token::Return => self.parse_return_statement(),
_ => self.parse_expression_statement(),
}
}
fn parse_let_statement(&mut self) -> Option<Statement> {
let curr_token = self.curr_token.clone();
if !self.expect_peek(Token::Ident("".to_string())) {
return None;
}
let name = Identifier {
token: self.curr_token.clone(),
value: match &self.curr_token {
Token::Ident(value) => value.clone(),
_ => unreachable!(),
},
};
if !self.expect_peek(Token::Assign) {
return None;
}
self.next_token();
let value = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
if self.peek_token_is(Token::Semicolon) {
self.next_token();
}
Some(Statement::Let(LetStatement {
token: curr_token,
name,
value,
}))
}
fn parse_return_statement(&mut self) -> Option<Statement> {
let curr_token = self.curr_token.clone();
self.next_token();
let return_value = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
if self.peek_token_is(Token::Semicolon) {
self.next_token();
}
Some(Statement::Return(ReturnStatement {
token: curr_token,
return_value,
}))
}
fn parse_expression_statement(&mut self) -> Option<Statement> {
let curr_token = self.curr_token.clone();
let expression = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
let stmt = Statement::Expression(ExpressionStatement {
token: curr_token,
expression,
});
if self.peek_token_is(Token::Semicolon) {
self.next_token();
}
Some(stmt)
}
fn parse_expression(&mut self, precedence: Precedence) -> Option<Expression> {
let prefix = match self.prefix_parse_fns.get(&self.curr_token) {
Some(prefix_fn) => prefix_fn,
None => {
self.no_prefix_parse_fn_error(&self.curr_token);
return None;
}
};
let mut left_exp = prefix(self)?;
while !self.peek_token_is(Token::Semicolon) && precedence < Precedence::from(&self.peek_token)
{
let infix = match self.infix_parse_fns.get(&self.peek_token) {
Some(infix_fn) => infix_fn,
None => return Some(left_exp),
};
self.next_token();
left_exp = infix(self, left_exp)?;
}
Some(left_exp)
}
fn parse_identifier(&mut self) -> Option<Expression> {
Some(Expression::Identifier(Identifier {
token: self.curr_token.clone(),
value: match &self.curr_token {
Token::Ident(value) => value.clone(),
_ => unreachable!(),
},
}))
}
fn parse_integer_literal(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
let value = match &self.curr_token {
Token::Int(value) => match value.parse::<i64>() {
Ok(v) => v,
Err(_) => {
self.errors.push(format!(
"could not parse {} as integer",
value.to_string()
));
return None;
}
},
_ => unreachable!(),
};
Some(Expression::IntegerLiteral(IntegerLiteral { token, value }))
}
fn parse_prefix_expression(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
let operator = match &self.curr_token {
Token::Bang => "!".to_string(),
Token::Minus => "-".to_string(),
_ => unreachable!(),
};
self.next_token();
let right = match self.parse_expression(Precedence::Prefix) {
Some(expr) => Box::new(expr),
None => return None,
};
Some(Expression::PrefixExpression(PrefixExpression {
token,
operator,
right,
}))
}
fn parse_infix_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.curr_token.clone();
let operator = match &self.curr_token {
Token::Plus => "+".to_string(),
Token::Minus => "-".to_string(),
Token::Asterisk => "*".to_string(),
Token::Slash => "/".to_string(),
Token::Equal => "==".to_string(),
Token::NotEqual => "!=".to_string(),
Token::LessThan => "<".to_string(),
Token::GreaterThan => ">".to_string(),
_ => unreachable!(),
};
let precedence = Precedence::from(&self.curr_token);
self.next_token();
let right = match self.parse_expression(precedence) {
Some(expr) => Box::new(expr),
None => return None,
};
Some(Expression::InfixExpression(InfixExpression {
token,
left: Box::new(left),
operator,
right,
}))
}
fn parse_boolean(&mut self) -> Option<Expression> {
Some(Expression::Boolean(Boolean {
token: self.curr_token.clone(),
value: self.curr_token_is(Token::True),
}))
}
fn parse_grouped_expression(&mut self) -> Option<Expression> {
self.next_token();
let exp = self.parse_expression(Precedence::Lowest);
if !self.expect_peek(Token::RParen) {
return None;
}
exp
}
fn parse_if_expression(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
if !self.expect_peek(Token::LParen) {
return None;
}
self.next_token();
let condition = match self.parse_expression(Precedence::Lowest) {
Some(expr) => Box::new(expr),
None => return None,
};
if !self.expect_peek(Token::RParen) {
return None;
}
if !self.expect_peek(Token::LBrace) {
return None;
}
let consequence = self.parse_block_statement();
let alternative = if self.peek_token_is(Token::Else) {
self.next_token();
if !self.expect_peek(Token::LBrace) {
return None;
}
Some(self.parse_block_statement())
} else {
None
};
Some(Expression::IfExpression(IfExpression {
token,
condition,
consequence,
alternative,
}))
}
fn parse_block_statement(&mut self) -> BlockStatement {
let token = self.curr_token.clone();
let mut statements = Vec::new();
self.next_token();
while !self.curr_token_is(Token::RBrace) && !self.curr_token_is(Token::Eof) {
if let Some(stmt) = self.parse_statement() {
statements.push(stmt);
}
self.next_token();
}
BlockStatement { token, statements }
}
fn parse_function_literal(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
if !self.expect_peek(Token::LParen) {
return None;
}
let parameters = self.parse_function_parameters();
if !self.expect_peek(Token::LBrace) {
return None;
}
let body = self.parse_block_statement();
Some(Expression::FunctionLiteral(FunctionLiteral {
token,
parameters,
body,
}))
}
fn parse_function_parameters(&mut self) -> Vec<Identifier> {
let mut identifiers = Vec::new();
if self.peek_token_is(Token::RParen) {
self.next_token();
return identifiers;
}
self.next_token();
identifiers.push(Identifier {
token: self.curr_token.clone(),
value: match &self.curr_token {
Token::Ident(value) => value.clone(),
_ => unreachable!(),
},
});
while self.peek_token_is(Token::Comma) {
self.next_token();
self.next_token();
identifiers.push(Identifier {
token: self.curr_token.clone(),
value: match &self.curr_token {
Token::Ident(value) => value.clone(),
_ => unreachable!(),
},
});
}
if !self.expect_peek(Token::RParen) {
return Vec::new();
}
identifiers
}
fn parse_call_expression(&mut self, function: Expression) -> Option<Expression> {
let token = self.curr_token.clone();
let arguments = self.parse_expression_list(Token::RParen);
Some(Expression::CallExpression(CallExpression {
token,
function: Box::new(function),
arguments,
}))
}
fn parse_string_literal(&mut self) -> Option<Expression> {
Some(Expression::StringLiteral(StringLiteral {
token: self.curr_token.clone(),
value: match &self.curr_token {
Token::String(value) => value.clone(),
_ => unreachable!(),
},
}))
}
fn parse_array_literal(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
let elements = self.parse_expression_list(Token::RBracket);
Some(Expression::ArrayLiteral(ArrayLiteral { token, elements }))
}
fn parse_expression_list(&mut self, end: Token) -> Vec<Expression> {
let mut list = Vec::new();
if self.peek_token_is(end.clone()) {
self.next_token();
return list;
}
self.next_token();
list.push(match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return list,
});
while self.peek_token_is(Token::Comma) {
self.next_token();
self.next_token();
list.push(match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return list,
});
}
if !self.expect_peek(end) {
return Vec::new();
}
list
}
fn parse_index_expression(&mut self, left: Expression) -> Option<Expression> {
let token = self.curr_token.clone();
self.next_token();
let index = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
if !self.expect_peek(Token::RBracket) {
return None;
}
Some(Expression::IndexExpression(IndexExpression {
token,
left: Box::new(left),
index: Box::new(index),
}))
}
fn parse_hash_literal(&mut self) -> Option<Expression> {
let token = self.curr_token.clone();
let mut pairs = Vec::new();
while !self.peek_token_is(Token::RBrace) {
self.next_token();
let key = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
if !self.expect_peek(Token::Colon) {
return None;
}
self.next_token();
let value = match self.parse_expression(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};
pairs.push((key, value));
if !self.peek_token_is(Token::RBrace) && !self.expect_peek(Token::Comma) {
return None;
}
}
if !self.expect_peek(Token::RBrace) {
return None;
}
Some(Expression::HashLiteral(HashLiteral { token, pairs }))
}
fn curr_token_is(&self, token: Token) -> bool {
match (&self.curr_token, &token) {
(Token::Ident(_), Token::Ident(_)) => true,
(Token::Int(_), Token::Int(_)) => true,
(Token::String(_), Token::String(_)) => true,
(t1, t2) => t1 == t2,
}
}
fn peek_token_is(&self, token: Token) -> bool {
match (&self.peek_token, &token) {
(Token::Ident(_), Token::Ident(_)) => true,
(Token::Int(_), Token::Int(_)) => true,
(Token::String(_), Token::String(_)) => true,
(t1, t2) => t1 == t2,
}
}
fn expect_peek(&mut self, token: Token) -> bool {
if self.peek_token_is(token.clone()) {
self.next_token();
true
} else {
self.peek_error(token);
false
}
}
fn peek_error(&mut self, token: Token) {
let msg = format!(
"expected next token to be {:?}, got {:?} instead",
token, self.peek_token
);
self.errors.push(msg);
}
fn no_prefix_parse_fn_error(&mut self, token: &Token) {
let msg = format!("no prefix parse function for {:?} found", token);
self.errors.push(msg);
}
pub fn errors(&self) -> &Vec<String> {
&self.errors
}
}
End File# Shuumatsu/scarlet
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use crate::ast::*;
#[derive(Debug, Clone, PartialEq)]
pub enum Object {
Integer(i64),
Boolean(bool),
String(String),
Array(Vec<Object>),
Hash(HashMap<HashKey, HashPair>),
Function(Function),
Builtin(Builtin),
Return(Box<Object>),
Null,
}
impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Object::Integer(value) => write!(f, "{}", value),
Object::Boolean(value) => write!(f, "{}", value),
Object::String(value) => write!(f, "{}", value),
Object::Array(elements) => {
let elements_str: Vec<String> = elements.iter().map(|e| e.to_string()).collect();
write!(f, "[{}]", elements_str.join(", "))
}
Object::Hash(pairs) => {
let mut pairs_str = Vec::new();
for (key, pair) in pairs {
pairs_str.push(format!("{}: {}", key, pair.value));
}
write!(f, "{{{}}}", pairs_str.join(", "))
}
Object::Function(function) => {
let params: Vec<String> = function
.parameters
.iter()
.map(|p| p.to_string())
.collect();
write!(
f,
"fn({}) {{\n{}\n}}",
params.join(", "),
function.body.to_string()
)
}
Object::Builtin(_) => write!(f, "builtin function"),
Object::Return(value) => write!(f, "{}", value),
Object::Null => write!(f, "null"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Function {
pub parameters: Vec<Identifier>,
pub body: BlockStatement,
pub env: Environment,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Builtin {
pub name: String,
pub func: fn(Vec<Object>) -> Object,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum HashKey {
Integer(i64),
Boolean(bool),
String(String),
}
impl fmt::Display for HashKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HashKey::Integer(value) => write!(f, "{}", value),
HashKey::Boolean(value) => write!(f, "{}", value),
HashKey::String(value) => write!(f, "{}", value),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct HashPair {
pub key: Object,
pub value: Object,
}
pub trait Hashable {
fn hash_key(&self) -> Option<HashKey>;
}
impl Hashable for Object {
fn hash_key(&self) -> Option<Hash # Shuumatsu/scarlet
# src/evaluator/evaluator.rs
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use crate::ast::*;
use crate::object::*;
use crate::token::*;
pub fn eval(node: &Node, env: &mut Environment) -> Object {
match node {
Node::Program(program) => eval_program(&program.statements, env),
Node::Statement(stmt) => match stmt {
Statement::ExpressionStatement(expr_stmt) => {
eval(&Node::Expression(&expr_stmt.expression), env)
}
Statement::BlockStatement(block_stmt) => {
eval_block_statement(&block_stmt.statements, env)
}
Statement::LetStatement(let_stmt) => {
let val = eval(&Node::Expression(&let_stmt.value), env);
if is_error(&val) {
return val;
}
env.set(&let_stmt.name.value, val.clone());
val
}
Statement::ReturnStatement(return_stmt) => {
let val = eval(&Node::Expression(&return_stmt.return_value), env);
if is_error(&val) {
return val;
}
Object::Return(Box::new(val))
}
},
Node::Expression(expr) => match expr {
Expression::IntegerLiteral(int_lit) => Object::Integer(int_lit.value),
Expression::Boolean(bool_expr) => Object::Boolean(bool_expr.value),
Expression::PrefixExpression(prefix) => {
let right = eval(&Node::Expression(&prefix.right), env);
if is_error(&right) {
return right;
}
eval_prefix_expression(&prefix.operator, right)
}
Expression::InfixExpression(infix) => {
let left = eval(&Node::Expression(&infix.left), env);
if is_error(&left) {
return left;
}
let right = eval(&Node::Expression(&infix.right), env);
if is_error(&right) {
return right;
}
eval_infix_expression(&infix.operator, left, right)
}
Expression::IfExpression(if_expr) => {
eval_if_expression(if_expr, env)
}
Expression::Identifier(ident) => eval_identifier(ident, env),
Expression::FunctionLiteral(func_lit) => {
let params = func_lit.parameters.clone();
let body = func_lit.body.clone();
Object::Function(Function {
parameters: params,
body,
env: env.clone(),
})
}
Expression::CallExpression(call_expr) => {
let function = eval(&Node::Expression(&call_expr.function), env);
if is_error(&function) {
return function;
}
let args = eval_expressions(&call_expr.arguments, env);
if args.len() == 1 && is_error(&args[0]) {
return args[0].clone();
}
apply_function(function, args)
}
Expression::StringLiteral(str_lit) => {
Object::String(str_lit.value.clone())
}
Expression::ArrayLiteral(array_lit) => {
let elements = eval_expressions(&array_lit.elements, env);
if elements.len() == 1 && is_error(&elements[0]) {
return elements[0].clone();
}
Object::Array(elements)
}
Expression::IndexExpression(index_expr) => {
let left = eval(&Node::Expression(&index_expr.left), env);
if is_error(&left) {
return left;
}
let index = eval(&Node::Expression(&index_expr.index), env);
if is_error(&index) {
return index;
}
eval_index_expression(left, index)
}
Expression::HashLiteral(hash_lit) => {
eval_hash_literal(hash_lit, env)
}
},
}
}
fn eval_program(stmts: &[Statement], env: &mut Environment) -> Object {
let mut result = Object::Null;
for statement in stmts {
result = eval(&Node::Statement(statement), env);
match result {
Object::Return(value) => return *value,
Object::Error(_) => return result,
_ => {}
}
}
result
}
fn eval_block_statement(stmts: &[Statement], env: &mut Environment) -> Object {
let mut result = Object::Null;
for statement in stmts {
result = eval(&Node::Statement(statement), env);
match result {
Object::Return(_) | Object::Error(_) => return result,
_ => {}
}
}
result
}
fn eval_prefix_expression(operator: &str, right: Object) -> Object {
match operator {
"!" => eval_bang_operator_expression(right),
"-" => eval_minus_prefix_operator_expression(right),
_ => Object::Error(format!("unknown operator: {}{}", operator, right.type_name())),
}
}
fn eval_bang_operator_expression(right: Object) -> Object {
match right {
Object::Boolean(true) => Object::Boolean(false),
Object::Boolean(false) => Object::Boolean(true),
Object::Null => Object::Boolean(true),
_ => Object::Boolean(false),
}
}
fn eval_minus_prefix_operator_expression(right: Object) -> Object {
match right {
Object::Integer(value) => Object::Integer(-value),
_ => Object::Error(format!("unknown operator: -{}", right.type_name())),
}
}
fn eval_infix_expression(operator: &str, left: Object, right: Object) -> Object {
match (&left, &right) {
(Object::Integer(left_val), Object::Integer(right_val)) => {
eval_integer_infix_expression(operator, *left_val, *right_val)
}
(Object::String(left_val), Object::String(right_val)) => {
eval_string_infix_expression(operator, left_val, right_val)
}
_ if left.type_name() != right.type_name() => {
Object::Error(format!(
"type mismatch: {} {} {}",
left.type_name(),
operator,
right.type_name()
))
}
_ => match operator {
"==" => Object::Boolean(left == right),
"!=" => Object::Boolean(left != right),
_ => Object::Error(format!(
"unknown operator: {} {} {}",
left.type_name(),
operator,
right.type_name()
)),
},
}
}
fn eval_integer_infix_expression(operator: &str, left: i64, right: i64) -> Object {
match operator {
"+" => Object::Integer(left + right),
"-" => Object::Integer(left - right),
"*" => Object::Integer(left * right),
"/" => Object::Integer(left / right),
"<" => Object::Boolean(left < right),
">" => Object::Boolean(left > right),
"==" => Object::Boolean(left == right),
"!=" => Object::Boolean(left != right),
_ => Object::Error(format!("unknown operator: INTEGER {} INTEGER", operator)),
}
}
fn eval_string_infix_expression(operator: &str, left: &str, right: &str) -> Object {
match operator {
"+" => Object::String(format!("{}{}", left, right)),
"==" => Object::Boolean(left == right),
"!=" => Object::Boolean(left != right),
_ => Object::Error(format!("unknown operator: STRING {} STRING", operator)),
}
}
fn eval_if_expression(if_expr: &IfExpression, env: &mut Environment) -> Object {
let condition = eval(&Node::Expression(&if_expr.condition), env);
if is_error(&condition) {
return condition;
}
if is_truthy(condition) {
eval(
&Node::Statement(&Statement::BlockStatement(if_expr.consequence.clone())),
env,
)
} else if let Some(alt) = &if_expr.alternative {
eval(&Node::Statement(&Statement::BlockStatement(alt.clone())), env)
} else {
Object::Null
}
}
fn is_truthy(obj: Object) -> bool {
match obj {
Object::Null => false,
Object::Boolean(false) => false,
_ => true,
}
}
fn eval_identifier(ident: &Identifier, env: &Environment) -> Object {
match env.get(&ident.value) {
Some(obj) => obj,
None => match get_builtin(&ident.value) {
Some(builtin) => Object::Builtin(builtin),
None => Object::Error(format!("identifier not found: {}", ident.value)),
},
}
}
fn eval_expressions(exprs: &[Expression], env: &mut Environment) -> Vec<Object> {
let mut result = Vec::new();
for expr in exprs {
let evaluated = eval(&Node::Expression(expr), env);
if is_error(&evaluated) {
return vec![evaluated];
}
result.push(evaluated);
}
result
}
fn apply_function(func: Object, args: Vec<Object>) -> Object {
match func {
Object::Function(function) => {
let mut extended_env = extend_function_env(&function, args);
let evaluated = eval(
&Node::Statement(&Statement::BlockStatement(function.body)),
&mut extended_env,
);
unwrap_return_value(evaluated)
}
Object::Builtin(builtin) => (builtin.func)(args),
_ => Object::Error(format!("not a function: {}", func.type_name())),
}
}
fn extend_function_env(func: &Function, args: Vec<Object>) -> Environment {
let mut env = Environment::new_enclosed(func.env.clone());
for (param_idx, param) in func.parameters.iter().enumerate() {
if param_idx < args.len() {
env.set(¶m.value, args[param_idx].clone());
}
}
env
}
fn unwrap_return_value(obj: Object) -> Object {
match obj {
Object::Return(value) => *value,
_ => obj,
}
}
fn eval_index_expression(left: Object, index: Object) -> Object {
match (&left, &index) {
(Object::Array(elements), Object::Integer(idx)) => {
eval_array_index_expression(elements, *idx)
}
(Object::Hash(pairs), _) => {
if let Some(key) = index.hash_key() {
match pairs.get(&key) {
Some(pair) => pair.value.clone(),
None => Object::Null,
}
} else {
Object::Error(format!("unusable as hash key: {}", index.type_name()))
}
}
_ => Object::Error(format!("index operator not supported: {}", left.type_name())),
}
}
fn eval_array_index_expression(array: &[Object], index: i64) -> Object {
let max = array.len() as i64 - 1;
if index < 0 || index > max {
return Object::Null;
}
array[index as usize].clone()
}
fn eval_hash_literal(hash: &HashLiteral, env: &mut Environment) -> Object {
let mut pairs = HashMap::new();
for (key_node, value_node) in &hash.pairs {
let key = eval(&Node::Expression(key_node), env);
if is_error(&key) {
return key;
}
let hash_key = match key.hash_key() {
Some(key) => key,
None => return Object::Error(format!("unusable as hash key: {}", key.type_name())),
};
let value = eval(&Node::Expression(value_node), env);
if is_error(&value) {
return value;
}
pairs.insert(hash_key, HashPair { key: key.clone(), value });
}
Object::Hash(pairs)
}
fn is_error(obj: &Object) -> bool {
matches!(obj, Object::Error(_))
}
// Builtins
fn get_builtin(name: &str) -> Option<Builtin> {
match name {
"len" => Some(Builtin {
name: "len".to_string(),
func: builtin_len,
}),
"first" => Some(Builtin {
name: "first".to_string(),
func: builtin_first,
}),
"last" => Some(Builtin {
name: "last".to_string(),
func: builtin_last,
}),
"rest" => Some(Builtin {
name: "rest".to_string(),
func: builtin_rest,
}),
"push" => Some(Builtin {
name: "push".to_string(),
func: builtin_push,
}),
"puts" => Some(Builtin {
name: "puts".to_string(),
func: builtin_puts,
}),
_ => None,
}
}
fn builtin_len(args: Vec<Object>) -> Object {
if args.len() != 1 {
return Object::Error(format!(
"wrong number of arguments. got={}, want=1",
args.len()
));
}
match &args[0] {
Object::String(s) => Object::Integer(s.len() as i64),
Object::Array(elements) => Object::Integer(elements.len() as i64),
_ => Object::Error(format!(
"argument to `len` not supported, got {}",
args[0].type_name()
)),
}
}
fn builtin_first(args: Vec<Object>) -> Object {
if args.len() != 1 {
return Object::Error(format!(
"wrong number of arguments. got={}, want=1",
args.len()
));
}
match &args[0] {
Object::Array(elements) => {
if elements.is_empty() {
Object::Null
} else {
elements[0].clone()
}
}
_ => Object::Error(format!(
"argument to `first` must be ARRAY, got {}",
args[0].type_name()
)),
}
}
fn builtin_last(args: Vec<Object>) -> Object {
if args.len() != 1 {
return Object::Error(format!(
"wrong number of arguments. got={}, want=1",
args.len()
));
}
match &args[0] {
Object::Array(elements) => {
if elements.is_empty() {
Object::Null
} else {
elements[elements.len() - 1].clone()
}
}
_ => Object::Error(format!(
"argument to `last` must be ARRAY, got {}",
args[0].type_name()
)),
}
}
fn builtin_rest(args: Vec<Object>) -> Object {
if args.len() != 1 {
return Object::Error(format!(
"wrong number of arguments. got={}, want=1",
args.len()
));
}
match &args[0] {
Object::Array(elements) => {
if elements.is_empty() {
Object::Null
} else {
let mut new_elements = elements.clone();
new_elements.remove(0);
Object::Array(new_elements)
}
}
_ => Object::Error(format!(
"argument to `rest` must be ARRAY, got {}",
args[0].type_name()
)),
}
}
fn builtin_push(args: Vec<Object>) -> Object {
if args.len() != 2 {
return Object::Error(format!(
"wrong number of arguments. got={}, want=2",
args.len()
));
}
match &args[0] {
Object::Array(elements) => {
let mut new_elements = elements.clone();
new_elements.push(args[1].clone());
Object::Array(new_elements)
}
_ => Object::Error(format!(
"argument to `push` must be ARRAY, got {}",
args[0].type_name()
)),
}
}
fn builtin_puts(args: Vec<Object>) -> Object {
for arg in args {
println!("{}", arg);
}
Object::Null
}
// Environment
#[derive(Debug, Clone, PartialEq)]
pub struct Environment {
store: HashMap<String, Object>,
outer: Option<Box<Environment>>,
}
impl Environment {
pub fn new() -> Self {
Environment {
store: HashMap::new(),
outer: None,
}
}
pub fn new_enclosed(outer: Environment) -> Self {
Environment {
store: HashMap::new(),
outer: Some(Box::new(outer)),
}
}
pub fn get(&self, name: &str) -> Option<Object> {
match self.store.get(name) {
Some(obj) => Some(obj.clone()),
None => match &self.outer {
Some(outer) => outer.get(name),
None => None,
},
}
}
pub fn set(&mut self, name: &str, val: Object) -> Object {
self.store.insert(name.to_string(), val.clone());
val
}
}
// Node enum for eval function
pub enum Node<'a> {
Program(&'a Program),
Statement(&'a Statement),
Expression(&'a Expression),
}
// Type name extension for Object
trait TypeName {
fn type_name(&self) -> String;
}
impl TypeName for Object {
fn type_name(&self) -> String {
match self {
Object::Integer(_) => "INTEGER".to_string(),
Object::Boolean(_) => "BOOLEAN".to_string(),
Object::String(_) => "STRING".to_string(),
Object::Array(_) => "ARRAY".to_string(),
Object::Hash(_) => "HASH".to_string(),
Object::Function(_) => "FUNCTION".to_string(),
Object::Builtin(_) => "BUILTIN".to_string(),
Object::Return(_) => "RETURN".to_string(),
Object::Null => "NULL".to_string(),
Object::Error(_) => "ERROR".to_string(),
}
}
}
End File# Shuumatsu/scarlet
# src/ast/ast.rs
use std::fmt;
use crate::token::Token;
#[derive(Debug, Clone)]
pub struct Program {
pub statements: Vec<Statement>,
}
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for stmt in &self.statements {
write!(f, "{}", stmt)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub enum Statement {
Let(LetStatement),
Return(ReturnStatement),
Expression(ExpressionStatement),
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Statement::Let(stmt) => write!(f, "{}", stmt),
Statement::Return(stmt) => write!(f, "{}", stmt),
Statement::Expression(stmt) => write!(f, "{}", stmt),
}
}
}
#[derive(Debug, Clone)]
pub struct LetStatement {
pub token: Token,
pub name: Identifier,
pub value: Expression,
}
impl fmt::Display for LetStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} = {};", self.token, self.name, self.value)
}
}
#[derive(Debug, Clone)]
pub struct ReturnStatement {
pub token: Token,
pub return_value: Expression,
}
impl fmt::Display for ReturnStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {};", self.token, self.return_value)
}
}
#[derive(Debug, Clone)]
pub struct ExpressionStatement {
pub token: Token,
pub expression: Expression,
}
impl fmt::Display for ExpressionStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.expression)
}
}
#[derive(Debug, Clone)]
pub enum Expression {
Identifier(Identifier),
IntegerLiteral(IntegerLiteral),
PrefixExpression(PrefixExpression),
InfixExpression(InfixExpression),
Boolean(Boolean),
IfExpression(IfExpression),
FunctionLiteral(FunctionLiteral),
CallExpression(CallExpression),
StringLiteral(StringLiteral),
ArrayLiteral(ArrayLiteral),
IndexExpression(IndexExpression),
HashLiteral(HashLiteral),
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expression::Identifier(expr) => write!(f, "{}", expr),
Expression::IntegerLiteral(expr) => write!(f, "{}", expr),
Expression::PrefixExpression(expr) => write!(f, "{}", expr),
Expression::InfixExpression(expr) => write!(f, "{}", expr),
Expression::Boolean(expr) => write!(f, "{}", expr),
Expression::IfExpression(expr) => write!(f, "{}", expr),
Expression::FunctionLiteral(expr) => write!(f, "{}", expr),
Expression::CallExpression(expr) => write!(f, "{}", expr),
Expression::StringLiteral(expr) => write!(f, "{}", expr),
Expression::ArrayLiteral(expr) => write!(f, "{}", expr),
Expression::IndexExpression(expr) => write!(f, "{}", expr),
Expression::HashLiteral(expr) => write!(f, "{}", expr),
}
}
}
#[derive(Debug, Clone)]
pub struct Identifier {
pub token: Token,
pub value: String,
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Debug, Clone)]
pub struct IntegerLiteral {
pub token: Token,
pub value: i64,
}
impl fmt::Display for IntegerLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Debug, Clone)]
pub struct PrefixExpression {
pub token: Token,
pub operator: String,
pub right: Box<Expression>,
}
impl fmt::Display for PrefixExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}{})", self.operator, self.right)
}
}
#[derive(Debug, Clone)]
pub struct InfixExpression {
pub token: Token,
pub left: Box<Expression>,
pub operator: String,
pub right: Box<Expression>,
}
impl fmt::Display for InfixExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({} {} {})", self.left, self.operator, self.right)
}
}
#[derive(Debug, Clone)]
pub struct Boolean {
pub token: Token,
pub value: bool,
}
impl fmt::Display for Boolean {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Debug, Clone)]
pub struct IfExpression {
pub token: Token,
pub condition: Box<Expression>,
pub consequence: BlockStatement,
pub alternative: Option<BlockStatement>,
}
impl fmt::Display for IfExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "if {} {}", self.condition, self.consequence)?;
if let Some(alt) = &self.alternative {
write!(f, " else {}", alt)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct BlockStatement {
pub token: Token,
pub statements: Vec<Statement>,
}
impl fmt::Display for BlockStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for stmt in &self.statements {
write!(f, "{}", stmt)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct FunctionLiteral {
pub token: Token,
pub parameters: Vec<Identifier>,
pub body: BlockStatement,
}
impl fmt::Display for FunctionLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let params: Vec<String> = self.parameters.iter().map(|p| p.to_string()).collect();
write!(f, "{}({}) {}", self.token, params.join(", "), self.body)
}
}
#[derive(Debug, Clone)]
pub struct CallExpression {
pub token: Token,
pub function: Box<Expression>,
pub arguments: Vec<Expression>,
}
impl fmt::Display for CallExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let args: Vec<String> = self.arguments.iter().map(|a| a.to_string()).collect();
write!(f, "{}({})", self.function, args.join(", "))
}
}
#[derive(Debug, Clone)]
pub struct StringLiteral {
pub token: Token,
pub value: String,
}
impl fmt::Display for StringLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Debug, Clone)]
pub struct ArrayLiteral {
pub token: Token,
pub elements: Vec<Expression>,
}
impl fmt::Display for ArrayLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let elements: Vec<String> = self.elements.iter().map(|e| e.to_string()).collect();
write!(f, "[{}]", elements.join(", "))
}
}
#[derive(Debug, Clone)]
pub struct IndexExpression {
pub token: Token,
pub left: Box<Expression>,
pub index: Box<Expression>,
}
impl fmt::Display for IndexExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}[{}])", self.left, self.index)
}
}
#[derive(Debug, Clone)]
pub struct HashLiteral {
pub token: Token,
pub pairs: Vec<(Expression, Expression)>,
}
impl fmt::Display for HashLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let pairs: Vec<String> = self
.pairs
.iter()
.map(|(k, v)| format!("{}:{}", k, v))
.collect();
write!(f, "{{{}}}", pairs.join(", "))
}
}
End File# Shuumatsu/scarlet
# src/token/token.rs
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
Illegal,
Eof,
// Identifiers + literals
Ident(String),
Int(String),
String(String),
// Operators
Assign,
Plus,
Minus,
Bang,
Asterisk,
Slash,
LessThan,
GreaterThan,
Equal,
NotEqual,
// Delimiters
Comma,
Semicolon,
Colon,
LParen,
RParen,
LBrace,
RBrace,
LBracket,
RBracket,
// Keywords
Function,
Let,
True,
False,
If,
Else,
Return,
}
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Token::Illegal => write!(f, "ILLEGAL"),
Token::Eof => write!(f, "EOF"),
Token::Ident(s) => write!(f, "{}", s),
Token::Int(s) => write!(f, "{}", s),
Token::String(s) => write!(f, "\"{}\"", s),
Token::Assign => write!(f, "="),
Token::Plus => write!(f, "+"),
Token::Minus => write!(f, "-"),
Token::Bang => write!(f, "!"),
Token::Asterisk => write!(f, "*"),
Token::Slash => write!(f, "/"),
Token::LessThan => write!(f, "<"),
Token::GreaterThan => write!(f, ">"),
Token::Equal => write!(f, "=="),
Token::NotEqual => write!(f, "!="),
Token::Comma => write!(f, ","),
Token::Semicolon => write!(f, ";"),
Token::Colon => write!(f, ":"),
Token::LParen => write!(f, "("),
Token::RParen => write!(f, ")"),
Token::LBrace => write!(f, "{{"),
Token::RBrace => write!(f, "}}"),
Token::LBracket => write!(f, "["),
Token::RBracket => write!(f, "]"),
Token::Function => write!(f, "fn"),
Token::Let => write!(f, "let"),
Token::True => write!(f, "true"),
Token::False => write!(f, "false"),
Token::If => write!(f, "if"),
Token::Else => write!(f, "else"),
Token::Return => write!(f, "return"),
}
}
}
pub fn lookup_ident(ident: &str) -> Token {
match ident {
"fn" => Token::Function,
"let" => Token::Let,
"true" => Token::True,
"false" => Token::False,
"if" => Token::If,
"else" => Token::Else,
"return" => Token::Return,
_ => Token::Ident(ident.to_string()),
}
}
End File# Shuumatsu/scarlet
# src/lexer/lexer.rs
use crate::token::*;
pub struct Lexer {
input: Vec<char>,
position: usize, // current position in input (points to current char)
read_position: usize, // current reading position in input (after current char)
ch: char, // current char under examination
}
impl Lexer {
pub fn new(input: &str) -> Self {
let mut lexer = Lexer {
input: input.chars().collect(),
position: 0,
read_position: 0,
ch: '\0',
};
lexer.read_char();
lexer
}
fn read_char(&mut self) {
if self.read_position >= self.input.len() {
self.ch = '\0';
} else {
self.ch = self.input[self.read_position];
}
self.position = self.read_position;
self.read_position += 1;
}
fn peek_char(&self) -> char {
if self.read_position >= self.input.len() {
'\0'
} else {
self.input[self.read_position]
}
}
pub fn next_token(&mut self) -> Token {
self.skip_whitespace();
let token = match self.ch {
'=' => {
if self.peek_char() == '=' {
self.read_char();
Token::Equal
} else {
Token::Assign
}
}
'+' => Token::Plus,
'-' => Token::Minus,
'!' => {
if self.peek_char() == '=' {
self.read_char();
Token::NotEqual
} else {
Token::Bang
}
}
'*' => Token::Asterisk,
'/' => Token::Slash,
'<' => Token::LessThan,
'>' => Token::GreaterThan,
',' => Token::Comma,
';' => Token::Semicolon,
':' => Token::Colon,
'(' => Token::LParen,
')' => Token::RParen,
'{' => Token::LBrace,
'}' => Token::RBrace,
'[' => Token::LBracket,
']' => Token::RBracket,
'"' => {
let str_val = self.read_string();
Token::String(str_val)
}
'\0' => Token::Eof,
_ => {
if is_letter(self.ch) {
let ident = self.read_identifier();
return lookup_ident(&ident);
} else if is_digit(self.ch) {
let num = self.read_number();
return Token::Int(num);
} else {
Token::Illegal
}
}
};
self.read_char();
token
}
fn read_identifier(&mut self) -> String {
let position = self.position;
while is_letter(self.ch) || is_digit(self.ch) {
self.read_char();
}
self.input[position..self.position].iter().collect()
}
fn read_number(&mut self) -> String {
let position = self.position;
while is_digit(self.ch) {
self.read_char();
}
self.input[position..self.position].iter().collect()
}
fn read_string(&mut self) -> String {
let position = self.position + 1;
loop {
self.read_char();
if self.ch == '"' || self.ch == '\0' {
break;
}
}
self.input[position..self.position].iter().collect()
}
fn skip_whitespace(&mut self) {
while self.ch.is_whitespace() {
self.read_char();
}
}
}
fn is_letter(ch: char) -> bool {
ch.is_alphabetic() || ch == '_'
}
fn is_digit(ch: char) -> bool {
ch.is_digit(10)
}
End File# Shuumatsu/scarlet
# src/repl/repl.rs
use std::io::{self, Write};
use crate::evaluator::*;
use crate::lexer::*;
use crate::object::*;
use crate::parser::*;
const PROMPT: &str = ">> ";
pub fn start() {
let mut env = Environment::new();
loop {
print!("{}", PROMPT);
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
if input.trim() == "exit" {
break;
}
let lexer = Lexer::new(&input);
let mut parser = Parser::new(lexer);
let program = parser.parse_program();
if !parser.errors().is_empty() {
print_parser_errors(parser.errors());
continue;
}
let evaluated = eval(&Node::Program(&program), &mut env);
println!("{}", evaluated);
}
}
fn print_parser_errors(errors: &[String]) {
println!("Woops! We ran into some monkey business here!");
println!(" parser errors:");
for error in errors {
println!("\t{}", error);
}
}
End File# Shuumatsu/scarlet
# src/main.rs
use std::io::{self, Write};
use std::env;
use std::fs;
mod token;
mod lexer;
mod ast;
mod parser;
mod object;
mod evaluator;
mod repl;
use crate::evaluator::*;
use crate::lexer::*;
use crate::object::*;
use crate::parser::*;
use crate::repl::*;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
// Run file mode
let filename = &args[1];
match fs::read_to_string(filename) {
Ok(content) => {
let mut env = Environment::new();
let lexer = Lexer::new(&content);
let mut parser = Parser::new(lexer);
let program = parser.parse_program();
if !parser.errors().is_empty() {
print_parser_errors(parser.errors());
return;
}
let evaluated = eval(&Node::Program(&program), &mut env);
// Only print the result if it's not null (to avoid cluttering output)
if !matches!(evaluated, Object::Null) {
println!("{}", evaluated);
}
},
Err(e) => {
eprintln!("Error reading file '{}': {}", filename, e);
}
}
} else {
// REPL mode
println!("Welcome to Scarlet Programming Language!");
println!("Feel free to type in commands");
repl::start();
}
}
fn print_parser_errors(errors: &[String]) {
eprintln!("Parser errors:");
for error in errors {
eprintln!("\t{}", error);
}
}
End File