var value parse and some
This commit is contained in:
parent
f0d129b3e3
commit
b9fa8429a6
66
README.md
66
README.md
@ -1,3 +1,69 @@
|
|||||||
# Emcode
|
# Emcode
|
||||||
|
|
||||||
Embeddable code compiler
|
Embeddable code compiler
|
||||||
|
|
||||||
|
```
|
||||||
|
// comment
|
||||||
|
|
||||||
|
var a = 0 // create var (you can not create var without initial value)
|
||||||
|
a = 1 // int, set var
|
||||||
|
a = "123" // string, dynamic var type
|
||||||
|
a = {"11": "11"} // map (map<string, string>)
|
||||||
|
|
||||||
|
a."11" = "44" // set value to map item
|
||||||
|
|
||||||
|
a = {"11", "12"} // list (map<int, string>)
|
||||||
|
|
||||||
|
a.0 = "55" // set value to list element
|
||||||
|
|
||||||
|
a = 0.41 // float
|
||||||
|
|
||||||
|
var c = 10
|
||||||
|
|
||||||
|
c = c + a // addition (works with string+string=string)
|
||||||
|
c = c - a // subtraction
|
||||||
|
c = c * a // multiplication (works with string*int=string)
|
||||||
|
c = c / a // division
|
||||||
|
c = c % a // module
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// var types:
|
||||||
|
// int, float, map[key, value], string, null, function, bool
|
||||||
|
|
||||||
|
{
|
||||||
|
var b = 0
|
||||||
|
|
||||||
|
// this is scope
|
||||||
|
|
||||||
|
// <- here local vars for scope
|
||||||
|
}
|
||||||
|
|
||||||
|
// <- here global vars for scope
|
||||||
|
|
||||||
|
// global scope cant see local vars (var b in this case)
|
||||||
|
|
||||||
|
if a == 0.42 {
|
||||||
|
// works totally like scope
|
||||||
|
} else {
|
||||||
|
// has no else if or elif
|
||||||
|
}
|
||||||
|
|
||||||
|
// logical operations:
|
||||||
|
// a == b a equals b
|
||||||
|
// a >= b a greater than or equals b
|
||||||
|
// a <= b a less than or equals b
|
||||||
|
// a > b a greater than b
|
||||||
|
// a < b a less than b
|
||||||
|
// a != b a not equals b
|
||||||
|
// a || b a or b
|
||||||
|
// a && b a and b
|
||||||
|
// !a not a
|
||||||
|
|
||||||
|
var func = [arg, arg2] { // create function. also work like scope
|
||||||
|
return "123"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ["arg1", "arg2"] // run function
|
||||||
|
|
||||||
|
```
|
423
src/lib.rs
Normal file
423
src/lib.rs
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
use std::{collections::HashMap, fmt::{self, write}, hash::{Hash, Hasher}, sync::Arc};
|
||||||
|
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub trait Func {
|
||||||
|
fn args(&self) -> Vec<String>;
|
||||||
|
fn run(&self, globals: &mut VarList, args: VarList) -> Var;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Var {
|
||||||
|
Null,
|
||||||
|
Bool(bool),
|
||||||
|
Int(isize),
|
||||||
|
Float(f64),
|
||||||
|
String(String),
|
||||||
|
Map(HashMap<Var, Var>),
|
||||||
|
Func(Arc<dyn Func>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Var {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Var::Null => write!(f, "Null"),
|
||||||
|
Var::Bool(value) => write!(f, "Bool({})", value),
|
||||||
|
Var::Int(value) => write!(f, "Int({})", value),
|
||||||
|
Var::Float(value) => write!(f, "Float({})", value),
|
||||||
|
Var::String(value) => write!(f, "String({:?})", value),
|
||||||
|
Var::Map(map) => {
|
||||||
|
f.write_str("Map(")?;
|
||||||
|
let mut entries = map.iter();
|
||||||
|
if let Some((key, value)) = entries.next() {
|
||||||
|
write!(f, "{:?}: {:?}", key, value)?;
|
||||||
|
for (key, value) in entries {
|
||||||
|
write!(f, ", {:?}: {:?}", key, value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.write_str(")")
|
||||||
|
}
|
||||||
|
Var::Func(_) => write!(f, "Func(<function>)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Var {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Var::Null, Var::Null) => true,
|
||||||
|
(Var::Bool(a), Var::Bool(b)) => a == b,
|
||||||
|
(Var::Int(a), Var::Int(b)) => a == b,
|
||||||
|
(Var::Float(a), Var::Float(b)) => a == b,
|
||||||
|
(Var::String(a), Var::String(b)) => a == b,
|
||||||
|
(Var::Map(a), Var::Map(b)) => a.len() == b.len() && a.iter().all(|(k, v)| b.get(k) == Some(v)),
|
||||||
|
(Var::Func(a), Var::Func(b)) => Arc::ptr_eq(a, b),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Var {}
|
||||||
|
|
||||||
|
impl Hash for Var {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
match self {
|
||||||
|
Var::Null => state.write_u8(0),
|
||||||
|
Var::Bool(a) => state.write_u8(if *a { 1 } else { 0 }),
|
||||||
|
Var::Int(a) => state.write_isize(*a),
|
||||||
|
Var::Float(a) => state.write(&a.to_be_bytes()),
|
||||||
|
Var::String(a) => state.write(a.as_bytes()),
|
||||||
|
Var::Map(a) => a.iter().for_each(|o| o.hash(state)),
|
||||||
|
Var::Func(a) => Arc::as_ptr(a).hash(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Var {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Var::Null => write!(f, "null"),
|
||||||
|
Var::Bool(value) => write!(f, "{}", value),
|
||||||
|
Var::Int(value) => write!(f, "{}", value),
|
||||||
|
Var::Float(value) => write!(f, "{}", value),
|
||||||
|
Var::String(value) => write!(f, "\"{}\"", value),
|
||||||
|
Var::Map(map) => {
|
||||||
|
write!(f, "{}", "{")?;
|
||||||
|
let mut entries = map.iter();
|
||||||
|
if let Some((key, value)) = entries.next() {
|
||||||
|
write!(f, "{}: {}", key.to_string(), value.to_string())?;
|
||||||
|
for (key, value) in entries {
|
||||||
|
write!(f, ", {}: {}", key.to_string(), value.to_string())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "{}", "}")
|
||||||
|
}
|
||||||
|
Var::Func(_) => write!(f, "[] {}", "{}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ErrorType {
|
||||||
|
IntParse,
|
||||||
|
FloatParse,
|
||||||
|
UnknownVar,
|
||||||
|
FunctionArgs,
|
||||||
|
FunctionCode,
|
||||||
|
VarAlreadyInit,
|
||||||
|
VarDidntInit
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorType {
|
||||||
|
pub fn with_line(self, line: usize) -> Error {
|
||||||
|
Error { error_type: self, line }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Error {
|
||||||
|
error_type: ErrorType,
|
||||||
|
line: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Var {
|
||||||
|
fn replace_operation(a: &str, op: &str, b: &str, vars: &mut VarList) -> Result<String, ErrorType> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_operation(text: &str, vars: &mut VarList) -> Result<Var, ErrorType> {
|
||||||
|
let mut tokens = Vec::new();
|
||||||
|
let mut current_token = String::new();
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
for c in text.chars() {
|
||||||
|
match c {
|
||||||
|
'(' | ')' | '!' | '+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '|' | '&' => {
|
||||||
|
if !current_token.is_empty() {
|
||||||
|
tokens.push(current_token.clone());
|
||||||
|
current_token.clear();
|
||||||
|
}
|
||||||
|
if c == '(' {
|
||||||
|
stack.push(c.to_string());
|
||||||
|
} else if c == ')' {
|
||||||
|
while let Some(op) = stack.pop() {
|
||||||
|
if op == "(" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokens.push(op);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while let Some(top) = stack.last() {
|
||||||
|
let precedence_top = match top.as_str() {
|
||||||
|
"!" => 4,
|
||||||
|
"*" | "/" | "%" => 3,
|
||||||
|
"+" | "-" => 2,
|
||||||
|
"<" | "<=" | ">" | ">=" | "==" | "!=" => 1,
|
||||||
|
"&&" | "||" => 0,
|
||||||
|
_ => -1,
|
||||||
|
};
|
||||||
|
let precedence_current = match c {
|
||||||
|
'!' => 4,
|
||||||
|
'*' | '/' | '%' => 3,
|
||||||
|
'+' | '-' => 2,
|
||||||
|
'<' | '>' | '=' => 1,
|
||||||
|
'&' | '|' => 0,
|
||||||
|
_ => -1,
|
||||||
|
};
|
||||||
|
if precedence_top >= precedence_current {
|
||||||
|
tokens.push(stack.pop().unwrap());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack.push(c.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if c.is_whitespace() {
|
||||||
|
if !current_token.is_empty() {
|
||||||
|
tokens.push(current_token.clone());
|
||||||
|
current_token.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current_token.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !current_token.is_empty() {
|
||||||
|
tokens.push(current_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(op) = stack.pop() {
|
||||||
|
tokens.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rpn_stack: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
for token in tokens {
|
||||||
|
match token.as_str() {
|
||||||
|
"!" => {
|
||||||
|
let a = rpn_stack.pop().ok_or(ErrorType::UnknownVar)?;
|
||||||
|
let result = Self::replace_operation("false", "==", &a, vars)?;
|
||||||
|
rpn_stack.push(result);
|
||||||
|
}
|
||||||
|
"+" | "-" | "*" | "/" | "%" | "<" | "<=" | ">" | ">=" | "==" | "!=" | "&&" | "||" => {
|
||||||
|
let b = rpn_stack.pop().ok_or(ErrorType::UnknownVar)?;
|
||||||
|
let a = rpn_stack.pop().ok_or(ErrorType::UnknownVar)?;
|
||||||
|
let result = Self::replace_operation(&a, &token, &b, vars)?;
|
||||||
|
rpn_stack.push(result);
|
||||||
|
}
|
||||||
|
_ => rpn_stack.push(token),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(final_result) = rpn_stack.pop() {
|
||||||
|
Self::parse_value(&final_result, vars)
|
||||||
|
} else {
|
||||||
|
Err(ErrorType::UnknownVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_value(text: &str, vars: &mut VarList) -> Result<Var, ErrorType> {
|
||||||
|
if let Ok(v) = vars.get(text) {
|
||||||
|
return Ok(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((func, args)) = text[..text.len()-1].split_once("[") {
|
||||||
|
if text.ends_with("]") {
|
||||||
|
let mut args_vars = Vec::new();
|
||||||
|
for e in args.split(",").map(|o| o.trim().to_string()).collect::<Vec<String>>() {
|
||||||
|
args_vars.push(Self::parse_value(&e, vars)?);
|
||||||
|
}
|
||||||
|
if let Ok(Var::Func(v)) = vars.get(func) {
|
||||||
|
return Ok(v.run(vars,
|
||||||
|
VarList::new(
|
||||||
|
HashMap::from_iter(
|
||||||
|
v.args().iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, o)| (o.to_string(), args_vars[i].clone()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if text.starts_with("{") && text.ends_with("}") {
|
||||||
|
let text = text[1..text.len()-1].to_string();
|
||||||
|
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
let mut is_key = true;
|
||||||
|
let mut key = String::new();
|
||||||
|
let mut value = String::new();
|
||||||
|
let mut index = 0usize;
|
||||||
|
|
||||||
|
for char in text.chars() {
|
||||||
|
if char == '{' {
|
||||||
|
stack.push('{');
|
||||||
|
} else if char == '}' {
|
||||||
|
if let Some('{') = stack.last() {
|
||||||
|
stack.remove(stack.len()-1);
|
||||||
|
}
|
||||||
|
} else if stack.is_empty() {
|
||||||
|
if char == ':' {
|
||||||
|
is_key = false;
|
||||||
|
continue;
|
||||||
|
} else if char == ',' {
|
||||||
|
if is_key == true {
|
||||||
|
map.insert(Var::Int(index as isize), Var::parse_value(&key, vars)?);
|
||||||
|
index += 1;
|
||||||
|
} else {
|
||||||
|
map.insert(Var::parse_value(&key, vars)?, Var::parse_value(&value, vars)?);
|
||||||
|
}
|
||||||
|
is_key = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_key {
|
||||||
|
key.push(char);
|
||||||
|
} else {
|
||||||
|
value.push(char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Var::Map(map))
|
||||||
|
} else if text.starts_with("[") {
|
||||||
|
let (args, scope) = text[1..].split_once("]").ok_or(ErrorType::FunctionArgs)?;
|
||||||
|
let args = args.split(",").map(|o| o.trim().to_string()).collect::<Vec<String>>();
|
||||||
|
let code = scope[..scope.len()-1].split_once("{").ok_or(ErrorType::FunctionCode)?.1.to_string();
|
||||||
|
|
||||||
|
return Ok(Var::Func(Arc::new(CodeFunc::new(args, code))))
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::parse_raw_value(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_raw_value(text: &str) -> Result<Var, ErrorType> {
|
||||||
|
if text.starts_with("\"") && text.ends_with("\"") {
|
||||||
|
Ok(Var::String(text[1..text.len()-1].to_string()))
|
||||||
|
} else if text == "null" {
|
||||||
|
Ok(Var::Null)
|
||||||
|
} else if text == "true" {
|
||||||
|
Ok(Var::Bool(true))
|
||||||
|
} else if text == "false" {
|
||||||
|
Ok(Var::Bool(false))
|
||||||
|
} else if text.contains(".") {
|
||||||
|
Ok(Var::Float(text.parse().or(Err(ErrorType::FloatParse))?))
|
||||||
|
} else {
|
||||||
|
Ok(Var::Int(text.parse().or(Err(ErrorType::IntParse))?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VarList {
|
||||||
|
vars: HashMap<String, Var>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarList {
|
||||||
|
pub fn new(vars: HashMap<String, Var>) -> VarList {
|
||||||
|
VarList { vars }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self, name: String, value: Var) -> Result<(), ErrorType> {
|
||||||
|
if self.has(&name) {
|
||||||
|
return Err(ErrorType::VarAlreadyInit)
|
||||||
|
}
|
||||||
|
|
||||||
|
self._set(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, name: String, value: Var) -> Result<(), ErrorType> {
|
||||||
|
if !self.has(&name) {
|
||||||
|
return Err(ErrorType::VarDidntInit)
|
||||||
|
}
|
||||||
|
|
||||||
|
self._set(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn del(&mut self, name: &str) -> Result<(), ErrorType> {
|
||||||
|
if name.contains(".") {
|
||||||
|
let mut parts = name.split(".");
|
||||||
|
|
||||||
|
if let Some(var) = parts.next() {
|
||||||
|
if let Some(Var::Map(map)) = self.vars.get_mut(var) {
|
||||||
|
let parts_len = parts.clone().count() - 1;
|
||||||
|
let mut now_map = map;
|
||||||
|
let mut key;
|
||||||
|
|
||||||
|
for (i, part) in parts.enumerate() {
|
||||||
|
key = Var::parse_raw_value(part)?;
|
||||||
|
|
||||||
|
if i == parts_len - 1 {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if let Some(Var::Map(next_map)) = now_map.get_mut(&key) {
|
||||||
|
now_map = next_map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
now_map.remove(&key);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorType::UnknownVar)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ErrorType::UnknownVar)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.vars.remove(name).ok_or(ErrorType::UnknownVar).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _set(&mut self, name: String, value: Var) -> Result<(), ErrorType> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has(&self, name: &str) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, name: &str) -> Result<Var, ErrorType> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list(&self) -> HashMap<String, Var> {
|
||||||
|
self.vars.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merge(&self, list: VarList) -> VarList {
|
||||||
|
let mut map = self.vars.clone();
|
||||||
|
for (k, v) in list.list() {
|
||||||
|
map.insert(k, v);
|
||||||
|
}
|
||||||
|
VarList::new(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeFunc {
|
||||||
|
args: Vec<String>,
|
||||||
|
code: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeFunc {
|
||||||
|
pub fn new(args: Vec<String>, code: String) -> CodeFunc {
|
||||||
|
CodeFunc { args, code }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Func for CodeFunc {
|
||||||
|
fn args(&self) -> Vec<String> {
|
||||||
|
self.args.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, globals: &mut VarList, args: VarList) -> Var {
|
||||||
|
let mut locals = args;
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
0
src/tests.rs
Normal file
0
src/tests.rs
Normal file
Loading…
Reference in New Issue
Block a user