feat(string): string as ascii like C
parent
f96b6c058c
commit
43b564ab0d
10
README.md
10
README.md
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue