feat(string): string as ascii like C

main
flavien 2023-12-12 22:31:14 +01:00
parent f96b6c058c
commit 43b564ab0d
No known key found for this signature in database
6 changed files with 48 additions and 43 deletions

View File

@ -58,18 +58,18 @@ var: z => val: 8
### syntax
- functions OK
- print statement OK
- string / char => indexing
- array / list / map => iterators
- string / char => indexing OK
- array / map => iterators
- read / write
- types declaration
- type checking before runtime
- types inference
- program arguments
- structs
- structs => methods (list container?)
- range
- import from other files
- refactor parsing error printing
- unit tests
- better tests / unit tests
- check and modify parsing error printing
### tools
- repl
- LLVM IR translation

View File

@ -6,8 +6,8 @@ use crate::parser::syntax::{BinaryOp, Expr, UnaryOp, Value};
pub trait ValueCompute {
fn int(&self) -> Result<i64, String>;
fn truth(&self) -> Result<bool, String>;
fn str(&self) -> Result<Rc<String>, String>;
fn char(&self) -> Result<char, String>;
fn str(&self) -> Result<Rc<Vec<u8>>, String>;
fn char(&self) -> Result<u8, String>;
}
impl ValueCompute for Value {
@ -22,17 +22,17 @@ impl ValueCompute for Value {
Value::Boolean(b) => Ok(*b),
Value::Number(value) => Ok(*value != 0),
Value::String(string) => Ok(!string.is_empty()),
Value::Char(c) => Ok(*c != '\0'),
Value::Char(c) => Ok(*c != b'\0'),
_ => Err(format!("{} is not a logical value", self)),
}
}
fn str(&self) -> Result<Rc<String>, String> {
fn str(&self) -> Result<Rc<Vec<u8>>, String> {
match self {
Value::String(s) => Ok(s.clone()),
_ => Err(format!("{} is not a string", self)),
}
}
fn char(&self) -> Result<char, String> {
fn char(&self) -> Result<u8, String> {
match self {
Value::Char(c) => Ok(*c),
_ => Err(format!("{} is not a char", self)),
@ -59,7 +59,7 @@ impl UnaryCompute for UnaryOp {
value.len()
));
}
Value::Char(value.chars().nth(index as usize).unwrap())
Value::Char(value[index as usize])
}
})
}
@ -86,33 +86,40 @@ impl BinaryCompute for BinaryOp {
BinaryOp::Addition => match (left.evaluate(env)?, right.evaluate(env)?) {
(Value::Number(l), Value::Number(r)) => Ok(Value::Number(l + r)),
(Value::String(l), Value::Char(r)) => {
Ok(Value::String(Rc::new(format!("{}{}", l, r))))
let mut copy = Vec::with_capacity(l.len() + 1);
copy.extend_from_slice(&l);
copy.push(r);
Ok(Value::String(Rc::new(copy)))
}
(Value::Char(l), Value::String(r)) => {
Ok(Value::String(Rc::new(format!("{}{}", l, r))))
let mut copy = Vec::with_capacity(r.len() + 1);
copy.push(l);
copy.extend_from_slice(&r);
Ok(Value::String(Rc::new(copy)))
}
(Value::Char(l), Value::Char(r)) => Ok(Value::Char((l as u8 + r as u8) as char)),
(Value::Char(l), Value::Number(r)) => Ok(Value::Char((l as u8 + r as u8) as char)),
(Value::Number(l), Value::Char(r)) => Ok(Value::Char((l as u8 + r as u8) as char)),
(Value::Char(l), Value::Char(r)) => Ok(Value::Char(l + r)),
(Value::Char(l), Value::Number(r)) => Ok(Value::Char(l + r as u8)),
(Value::Number(l), Value::Char(r)) => Ok(Value::Char(l as u8 + r)),
(Value::String(l), Value::String(r)) => {
Ok(Value::String(Rc::new(format!("{}{}", l, r))))
let new = l.iter().chain(r.iter()).copied().collect();
Ok(Value::String(Rc::new(new)))
}
(l, r) => Err(format!("Cannot add {} to {}", l, r)),
},
BinaryOp::Subtraction => match (left.evaluate(env)?, right.evaluate(env)?) {
(Value::Number(l), Value::Number(r)) => Ok(Value::Number(l - r)),
(Value::Char(l), Value::Char(r)) => Ok(Value::Char((l as u8 - r as u8) as char)),
(Value::Char(l), Value::Number(r)) => Ok(Value::Char((l as u8 - r as u8) as char)),
(Value::Number(l), Value::Char(r)) => Ok(Value::Char((l as u8 - r as u8) as char)),
(Value::Char(l), Value::Char(r)) => Ok(Value::Char(l - r)),
(Value::Char(l), Value::Number(r)) => Ok(Value::Char(l - r as u8)),
(Value::Number(l), Value::Char(r)) => Ok(Value::Char(l as u8 - r)),
(l, r) => Err(format!("Cannot subtract {} from {}", r, l)),
},
BinaryOp::Multiplication => match (left.evaluate(env)?, right.evaluate(env)?) {
(Value::Number(l), Value::Number(r)) => Ok(Value::Number(l * r)),
(Value::Char(l), Value::Number(r)) => Ok(Value::String(Rc::new(
(0..r).map(|_| l).collect::<String>(),
(0..r).map(|_| l).collect::<Vec<u8>>(),
))),
(Value::Number(l), Value::Char(r)) => Ok(Value::String(Rc::new(
(0..l).map(|_| r).collect::<String>(),
(0..l).map(|_| r).collect::<Vec<u8>>(),
))),
(l, r) => Err(format!("Cannot multiply {} by {}", l, r)),
},

View File

@ -55,21 +55,20 @@ impl Execution for Stat {
if let Some(index) = index {
let index = index.evaluate(environment)?.int()?;
let value = expr.evaluate(environment)?.char()?;
let mut chars: Vec<char> = environment
let original = environment
.get(name)
.ok_or_else(|| format!("Variable {} not found", name))?
.str()?
.chars()
.collect();
if index < 0 || index >= chars.len() as i64 {
.str()?;
if index < 0 || index >= original.len() as i64 {
return Err(format!(
"Index {} out of bounds for string of length {}",
index,
chars.len()
original.len()
));
}
chars[index as usize] = value;
environment.add(name, Value::String(Rc::new(chars.into_iter().collect())));
let mut copy = (*original).clone();
copy[index as usize] = value;
environment.add(name, Value::String(Rc::new(copy)));
} else {
let value = expr.evaluate(environment)?;
environment.add(name, value);

View File

@ -6,7 +6,7 @@ pub mod machine;
#[cfg(test)]
mod tests {
use crate::parser::{ast::build_ast, syntax::Value};
use std::{fs::File, io::Read};
use std::{fs::File, io::Read, str};
use super::{
environment::{Environment, GlobalScope},
@ -277,26 +277,26 @@ mod tests {
Some(Value::String(value)) => value,
_ => panic!("x should be Value::String"),
};
assert!(*x == "hallo ");
assert!(str::from_utf8(&x).unwrap() == "hallo ");
let y = match environment.get("y") {
Some(Value::String(value)) => value,
_ => panic!("y should be Value::String"),
};
assert!(*y == "world");
assert!(str::from_utf8(&y).unwrap() == "world");
let z = match environment.get("z") {
Some(Value::String(value)) => value,
_ => panic!("z should be Value::String"),
};
assert!(*z == "hello world!");
assert!(str::from_utf8(&z).unwrap() == "hello world!");
let a = match environment.get("a") {
Some(Value::String(value)) => value,
_ => panic!("a should be Value::String"),
};
assert!(*a == "!!!");
assert!(str::from_utf8(&a).unwrap() == "!!!");
let b = match environment.get("b") {
Some(Value::Char(value)) => value,
_ => panic!("b should be Value::Char"),
};
assert!(b == 'l');
assert!(b == b'l');
}
}

View File

@ -71,12 +71,10 @@ fn build_expr(pair: Pair<Rule>) -> Result<Expr, String> {
Rule::call => build_call(primary),
Rule::string => {
let litteral = primary.as_str();
let value = litteral[1..litteral.len() - 1].to_string();
let value = litteral[1..litteral.len() - 1].as_bytes().to_vec();
Ok(Expr::Litteral(Value::String(Rc::new(value))))
}
Rule::char => Ok(Expr::Litteral(Value::Char(
primary.as_str().chars().nth(1).unwrap(),
))),
Rule::char => Ok(Expr::Litteral(Value::Char(primary.as_str().as_bytes()[1]))),
rule => Err(format!(
"atom expected number, boolean or variable, found {:?}",
rule

View File

@ -2,6 +2,7 @@
use std::{
fmt::{self, Display, Formatter},
rc::Rc,
str,
};
#[derive(Clone, Copy, Debug)]
@ -64,8 +65,8 @@ pub enum Value {
Number(i64),
Boolean(bool),
Function(Rc<Vec<String>>, Rc<Vec<Stat>>),
String(Rc<String>),
Char(char),
String(Rc<Vec<u8>>),
Char(u8),
None,
}
@ -90,7 +91,7 @@ impl Display for Value {
Value::Number(n) => write!(f, "{}", n),
Value::Boolean(b) => write!(f, "{}", b),
Value::Function(args, _) => write!(f, "fn({})", args.join(", ")),
Value::String(s) => write!(f, "{}", s),
Value::String(s) => unsafe { write!(f, "{}", str::from_utf8_unchecked(s)) },
Value::Char(c) => write!(f, "{}", c),
Value::None => write!(f, "None"),
}