structs
This commit is contained in:
parent
53bef7b5ed
commit
350f775b6c
7 changed files with 154 additions and 62 deletions
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc, cell::RefCell};
|
||||||
|
|
||||||
use num_traits::Pow;
|
use num_traits::Pow;
|
||||||
|
|
||||||
use crate::{value::{Value, Complex, func::{Func, CIterator}}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position, env::{EnvRef, Environment}};
|
use crate::{value::{Value, Complex, func::{Func, CIterator}, TypeData, CxprStruct}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position, env::{EnvRef, Environment}};
|
||||||
|
|
||||||
thread_local!(static PIPE_NAME: Option<Rc<str>> = Some(Rc::from("<pipeline>")));
|
thread_local!(static PIPE_NAME: Option<Rc<str>> = Some(Rc::from("<pipeline>")));
|
||||||
thread_local!(static FORLOOP_NAME: Option<Rc<str>> = Some(Rc::from("<for loop>")));
|
thread_local!(static FORLOOP_NAME: Option<Rc<str>> = Some(Rc::from("<for loop>")));
|
||||||
|
@ -127,7 +127,7 @@ pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> {
|
||||||
let value = eval_expr(expr, env)?;
|
let value = eval_expr(expr, env)?;
|
||||||
return Err(Unwind::Return { pos: pos.clone(), value })
|
return Err(Unwind::Return { pos: pos.clone(), value })
|
||||||
},
|
},
|
||||||
Stmt::Struct { .. } => todo!(),
|
Stmt::StructDef { name, ty } => env.borrow_mut().declare(name.ty.clone().as_ident().unwrap(), Value::Type(ty.clone()))
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,19 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
step.as_ref().map(|x| x.as_ref()),
|
step.as_ref().map(|x| x.as_ref()),
|
||||||
*incl, env),
|
*incl, env),
|
||||||
Expr::BoxedInfix { func } => Ok(Value::Func(func.clone())),
|
Expr::BoxedInfix { func } => Ok(Value::Func(func.clone())),
|
||||||
|
Expr::FieldAccess { target, name, .. } => {
|
||||||
|
let target = eval_expr(target, env)?;
|
||||||
|
match target {
|
||||||
|
Value::Struct(s) => {
|
||||||
|
if let Some(v) = s.data.clone().borrow().get(name.as_ref()) {
|
||||||
|
Ok(v.clone())
|
||||||
|
} else {
|
||||||
|
Err(format!("Struct {} has no field '{}'", Value::Struct(s).repr(), name).into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Err(format!("{} is not a struct", target.repr()).into())
|
||||||
|
}
|
||||||
|
},
|
||||||
Expr::List { items } => {
|
Expr::List { items } => {
|
||||||
let mut list = Vec::with_capacity(items.len());
|
let mut list = Vec::with_capacity(items.len());
|
||||||
for item in items {
|
for item in items {
|
||||||
|
@ -210,6 +223,29 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
};
|
};
|
||||||
Ok(Value::Func(func))
|
Ok(Value::Func(func))
|
||||||
},
|
},
|
||||||
|
Expr::StructInit { ty, args, .. } => {
|
||||||
|
let ty_val = eval_expr(&ty, env.clone())?;
|
||||||
|
let ty = match ty_val {
|
||||||
|
Value::Type(ty) => ty,
|
||||||
|
_ => return Err(format!("'{}' is not a type", ty_val.repr()).into())
|
||||||
|
};
|
||||||
|
match ty.typedata {
|
||||||
|
TypeData::None => Err(format!("'{}' is not a struct type", Value::Type(ty).repr()).into()),
|
||||||
|
TypeData::StructFields(ref fields) => if fields.len() == args.len() {
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
for (k, v) in fields.iter().zip(args.iter()) {
|
||||||
|
data.insert(k.to_owned(), eval_expr(v, env.clone())?);
|
||||||
|
}
|
||||||
|
let result = CxprStruct {
|
||||||
|
ty: ty.clone(),
|
||||||
|
data: Rc::new(RefCell::new(data))
|
||||||
|
};
|
||||||
|
Ok(Value::Struct(result))
|
||||||
|
} else {
|
||||||
|
Err(format!("Wrong number of fields for type '{}', expected {}, got {}", ty.name, fields.len(), args.len()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,44 +287,60 @@ fn compound_assignment_inner(l: Value, r: Value, op: &Token) -> Result<Value, Ru
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
// lhs must be an identifier (checked in parser)
|
match lhs {
|
||||||
if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = lhs {
|
Expr::Ident{value, ..} => {
|
||||||
if op.ty == TokenType::Equal {
|
let name = value.ty.clone().as_ident().unwrap();
|
||||||
// plain assignment
|
if op.ty == TokenType::Equal {
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
// plain assignment
|
||||||
env.borrow_mut()
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
.set(name.clone(), r.clone())
|
env.borrow_mut()
|
||||||
.map_err(|_| RuntimeError::new("Variable not declared before assignment", op.pos.clone()))?;
|
.set(name.clone(), r.clone())
|
||||||
Ok(r)
|
.map_err(|_| RuntimeError::new("Variable not declared before assignment", op.pos.clone()))?;
|
||||||
} else {
|
Ok(r)
|
||||||
// compound assignment
|
} else {
|
||||||
let prev_value = env.borrow_mut()
|
// compound assignment
|
||||||
.get(name)
|
let prev_value = env.borrow_mut()
|
||||||
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?;
|
.get(&name)
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?;
|
||||||
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
|
|
||||||
let result = compound_assignment_inner(prev_value, r, op)?;
|
let result = compound_assignment_inner(prev_value, r, op)?;
|
||||||
|
|
||||||
env.borrow_mut()
|
env.borrow_mut()
|
||||||
.set(name.clone(), result.clone()).expect("unreachable");
|
.set(name, result.clone()).expect("unreachable");
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
} else if let Expr::Index { lhs, index, pos } = lhs {
|
},
|
||||||
let l = eval_expr(lhs, env.clone())?;
|
Expr::Index { lhs, index, pos } => {
|
||||||
let idx = eval_expr(index, env.clone())?;
|
let l = eval_expr(lhs, env.clone())?;
|
||||||
if op.ty == TokenType::Equal {
|
let idx = eval_expr(index, env.clone())?;
|
||||||
|
if op.ty == TokenType::Equal {
|
||||||
|
let r = eval_expr(rhs, env)?;
|
||||||
|
l.assign_index(&idx, r.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||||
|
Ok(r)
|
||||||
|
} else {
|
||||||
|
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||||
|
let r = eval_expr(rhs, env)?;
|
||||||
|
let result = compound_assignment_inner(prev_value, r, op)?;
|
||||||
|
l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expr::FieldAccess { target, name, pos } => {
|
||||||
|
let target = eval_expr(target, env.clone())?;
|
||||||
let r = eval_expr(rhs, env)?;
|
let r = eval_expr(rhs, env)?;
|
||||||
l.assign_index(&idx, r.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
if let Value::Struct(s) = target {
|
||||||
Ok(r)
|
if s.data.borrow().contains_key(name.as_ref()) {
|
||||||
} else {
|
s.data.borrow_mut().insert(name.to_string(), r.clone());
|
||||||
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
Ok(r)
|
||||||
let r = eval_expr(rhs, env)?;
|
} else {
|
||||||
let result = compound_assignment_inner(prev_value, r, op)?;
|
Err(RuntimeError::new(format!("Struct {} does not have field {}", Value::Struct(s).repr(), name), pos.clone()))
|
||||||
l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
}
|
||||||
Ok(result)
|
} else {
|
||||||
|
Err(RuntimeError::new(format!("'{}' is not a struct", target.repr()), pos.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
_ => unreachable!()
|
||||||
unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::fmt;
|
use std::{fmt, rc::Rc};
|
||||||
|
|
||||||
use crate::{token::{Token, OpType}, Position, value::{Type, func::Func}};
|
use crate::{token::{Token, OpType}, Position, value::{Type, func::Func}};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub enum Stmt {
|
||||||
Continue { pos: Position },
|
Continue { pos: Position },
|
||||||
Return { pos: Position, expr: Expr },
|
Return { pos: Position, expr: Expr },
|
||||||
Fn { name: Token, args: Vec<Token>, body: Box<Stmt> },
|
Fn { name: Token, args: Vec<Token>, body: Box<Stmt> },
|
||||||
Struct { name: Token, ty: Type, items: Vec<Token> }
|
StructDef { name: Token, ty: Type },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Stmt {
|
impl fmt::Debug for Stmt {
|
||||||
|
@ -30,7 +30,7 @@ impl fmt::Debug for Stmt {
|
||||||
Self::Continue { .. } => write!(f, "(continue)"),
|
Self::Continue { .. } => write!(f, "(continue)"),
|
||||||
Self::Return { expr, .. } => write!(f, "(return {:?})", expr),
|
Self::Return { expr, .. } => write!(f, "(return {:?})", expr),
|
||||||
Self::Fn { name, args, body } => write!(f, "(fn {:?} {:?} {:?})", name, args, body),
|
Self::Fn { name, args, body } => write!(f, "(fn {:?} {:?} {:?})", name, args, body),
|
||||||
Self::Struct { name, ty, items } => write!(f, "(struct {:?} #{:?} {:?})", name, ty.id, items),
|
Self::StructDef { name, ty } => write!(f, "(struct {:?} #{:?})", name, ty.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,14 +41,16 @@ pub enum Expr {
|
||||||
Ternary { arg1: Box<Expr>, arg2: Box<Expr>, arg3: Box<Expr>, op: Token },
|
Ternary { arg1: Box<Expr>, arg2: Box<Expr>, arg3: Box<Expr>, op: Token },
|
||||||
Unary { arg: Box<Expr>, op: Token },
|
Unary { arg: Box<Expr>, op: Token },
|
||||||
Range { start: Box<Expr>, end: Option<Box<Expr>>, step: Option<Box<Expr>>, incl: bool },
|
Range { start: Box<Expr>, end: Option<Box<Expr>>, step: Option<Box<Expr>>, incl: bool },
|
||||||
|
FieldAccess { target: Box<Expr>, name: Rc<str>, pos: Position },
|
||||||
BoxedInfix { func: Func },
|
BoxedInfix { func: Func },
|
||||||
Ident { value: Token },
|
Ident { value: Token },
|
||||||
Literal { value: Token },
|
Literal { value: Token },
|
||||||
List { items: Vec<Expr> },
|
List { items: Vec<Expr> },
|
||||||
Map { items: Vec<(Expr,Expr)> },
|
Map { items: Vec<(Expr,Expr)> },
|
||||||
|
Fn { args: Vec<Token>, body: Box<Stmt> },
|
||||||
FuncCall { func: Box<Expr>, args: Vec<Expr>, pos: Position },
|
FuncCall { func: Box<Expr>, args: Vec<Expr>, pos: Position },
|
||||||
Index { lhs: Box<Expr>, index: Box<Expr>, pos: Position },
|
Index { lhs: Box<Expr>, index: Box<Expr>, pos: Position },
|
||||||
Fn { args: Vec<Token>, body: Box<Stmt> },
|
StructInit { ty: Box<Expr>, args: Vec<Expr>, pos: Position },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Expr {
|
impl fmt::Debug for Expr {
|
||||||
|
@ -58,6 +60,7 @@ impl fmt::Debug for Expr {
|
||||||
Self::Ternary { arg1, arg2, arg3, op} => write!(f, "({:?} {:?} {:?} {:?})", op, arg1, arg2, arg3),
|
Self::Ternary { arg1, arg2, arg3, op} => write!(f, "({:?} {:?} {:?} {:?})", op, arg1, arg2, arg3),
|
||||||
Self::Unary { arg, op } => write!(f, "({:?} {:?})", op, arg),
|
Self::Unary { arg, op } => write!(f, "({:?} {:?})", op, arg),
|
||||||
Self::Range { start, end, step, incl } => write!(f, "(range {:?}..{:?} step {:?} incl {:?})", start, end, step, incl),
|
Self::Range { start, end, step, incl } => write!(f, "(range {:?}..{:?} step {:?} incl {:?})", start, end, step, incl),
|
||||||
|
Self::FieldAccess { target, name, .. } => write!(f, "(fieldaccess {:?} {:?})", target, name),
|
||||||
Self::BoxedInfix { func } => write!(f, "(boxed-infix {:?})", func),
|
Self::BoxedInfix { func } => write!(f, "(boxed-infix {:?})", func),
|
||||||
Self::Ident { value } => write!(f, "(ident {:?})", value),
|
Self::Ident { value } => write!(f, "(ident {:?})", value),
|
||||||
Self::Literal { value } => write!(f, "(lit {:?})", value),
|
Self::Literal { value } => write!(f, "(lit {:?})", value),
|
||||||
|
@ -65,14 +68,15 @@ impl fmt::Debug for Expr {
|
||||||
Self::Map { items } => write!(f, "(map {:?})", items),
|
Self::Map { items } => write!(f, "(map {:?})", items),
|
||||||
Self::FuncCall { func, args, .. } => write!(f, "(call {:?} {:?})", func, args),
|
Self::FuncCall { func, args, .. } => write!(f, "(call {:?} {:?})", func, args),
|
||||||
Self::Index { lhs, index, .. } => write!(f, "(index {:?} {:?})", lhs, index),
|
Self::Index { lhs, index, .. } => write!(f, "(index {:?} {:?})", lhs, index),
|
||||||
Self::Fn { args, body } => write!(f, "(fn {:?} {:?})", args, body)
|
Self::Fn { args, body } => write!(f, "(fn {:?} {:?})", args, body),
|
||||||
|
Self::StructInit { ty, args, .. } => write!(f, "(mk-struct {:?} {:?})", ty, args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub fn is_lvalue(&self) -> bool {
|
pub fn is_lvalue(&self) -> bool {
|
||||||
matches!(self, Expr::Ident{..} | Expr::Index{..})
|
matches!(self, Expr::Ident{..} | Expr::Index{..} | Expr::FieldAccess{..})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_assignment(&self) -> bool {
|
pub fn is_assignment(&self) -> bool {
|
||||||
|
|
|
@ -150,7 +150,7 @@ impl Lexer {
|
||||||
match self.next() {
|
match self.next() {
|
||||||
'.' => match self.expect(&['.']) {
|
'.' => match self.expect(&['.']) {
|
||||||
Some('.') => self.add_token(TokenType::DoubleDot, ".."),
|
Some('.') => self.add_token(TokenType::DoubleDot, ".."),
|
||||||
_ => return Err(self.mk_error("Expected '.' after previous '.'"))
|
_ => self.add_token(TokenType::Dot, ".")
|
||||||
},
|
},
|
||||||
'+' => match self.expect(&['=']) {
|
'+' => match self.expect(&['=']) {
|
||||||
Some('=') => self.add_token(TokenType::PlusEqual, "+="),
|
Some('=') => self.add_token(TokenType::PlusEqual, "+="),
|
||||||
|
|
|
@ -273,8 +273,8 @@ impl Parser {
|
||||||
}
|
}
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let items = self.commalist(TokenType::RBrace, Self::ident)?;
|
let items = self.commalist(TokenType::RBrace, Self::ident)?;
|
||||||
let ty = value::generate_type(name);
|
let ty = value::generate_struct_type(name, items.iter().map(|x| x.ty.clone().as_ident().unwrap().to_string()).collect());
|
||||||
Ok(Stmt::Struct { name: tok_name, ty, items })
|
Ok(Stmt::StructDef { name: tok_name, ty })
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
|
@ -407,19 +407,33 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
if matches!(self.peek().ty, TokenType::Bang | TokenType::Minus) {
|
if matches!(self.peek().ty, TokenType::Bang | TokenType::Minus) {
|
||||||
let op = self.next();
|
let op = self.next();
|
||||||
Ok(Expr::Unary { arg: Box::new(self.fncall()?), op })
|
Ok(Expr::Unary { arg: Box::new(self.fieldaccess()?), op })
|
||||||
} else {
|
} else {
|
||||||
self.fncall()
|
self.fieldaccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function calls and array access
|
// dot notation for field access
|
||||||
fn fncall(&mut self) -> Result<Expr, ParserError> {
|
fn fieldaccess(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
let target = self.suffix()?;
|
||||||
|
if !self.at_end() && self.peek().ty == TokenType::Dot {
|
||||||
|
let pos = self.next().pos;
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let name = self.ident()?.ty.as_ident().unwrap();
|
||||||
|
Ok(Expr::FieldAccess { target: Box::new(target), name, pos })
|
||||||
|
} else {
|
||||||
|
Ok(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function calls, array access, struct initializaiton
|
||||||
|
fn suffix(&mut self) -> Result<Expr, ParserError> {
|
||||||
let mut expr = self.expr_base()?;
|
let mut expr = self.expr_base()?;
|
||||||
while !self.at_end() {
|
while !self.at_end() {
|
||||||
match self.peek().ty {
|
match self.peek().ty {
|
||||||
TokenType::LParen => expr = self.fncall_inner(expr)?,
|
TokenType::LParen => expr = self.fncall_inner(expr)?,
|
||||||
TokenType::LBrack => expr = self.arrindex_inner(expr)?,
|
TokenType::LBrack => expr = self.arrindex_inner(expr)?,
|
||||||
|
TokenType::LBrace => expr = self.structinit_inner(expr)?,
|
||||||
_ => return Ok(expr)
|
_ => return Ok(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,6 +458,13 @@ impl Parser {
|
||||||
Ok(Expr::Index { lhs: Box::new(expr), index: Box::new(index), pos: lbrack.pos })
|
Ok(Expr::Index { lhs: Box::new(expr), index: Box::new(index), pos: lbrack.pos })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct initialization: A { b }
|
||||||
|
fn structinit_inner(&mut self, expr: Expr) -> Result<Expr, ParserError> {
|
||||||
|
let lbrace = self.next();
|
||||||
|
let args = self.commalist(TokenType::RBrace, Self::assignment)?;
|
||||||
|
Ok(Expr::StructInit { ty: Box::new(expr), args, pos: lbrace.pos })
|
||||||
|
}
|
||||||
|
|
||||||
// key-value pairs for maps
|
// key-value pairs for maps
|
||||||
fn kv_pair(&mut self) -> Result<(Expr, Expr), ParserError> {
|
fn kv_pair(&mut self) -> Result<(Expr, Expr), ParserError> {
|
||||||
let key = self.assignment()?;
|
let key = self.assignment()?;
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn fn_copy(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
Value::List(l) => Value::from(l.borrow().clone()),
|
Value::List(l) => Value::from(l.borrow().clone()),
|
||||||
Value::Map(m) => Value::from(m.borrow().clone()),
|
Value::Map(m) => Value::from(m.borrow().clone()),
|
||||||
// Value::Func(f) => Value::Func(f.make_copy()) // TODO copy functions
|
// Value::Func(f) => Value::Func(f.make_copy()) // TODO copy functions
|
||||||
Value::Data(_) => todo!(),
|
Value::Struct(_) => todo!(),
|
||||||
a => a.clone(),
|
a => a.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub enum TokenType {
|
||||||
Bang, DoubleAmper, DoublePipe,
|
Bang, DoubleAmper, DoublePipe,
|
||||||
Tilde, Amper, Pipe,
|
Tilde, Amper, Pipe,
|
||||||
|
|
||||||
DoubleDot,
|
Dot, DoubleDot,
|
||||||
|
|
||||||
Equal, PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, DoubleSlashEqual, CaretEqual,
|
Equal, PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, DoubleSlashEqual, CaretEqual,
|
||||||
DoubleEqual, BangEqual, Greater, GreaterEqual, Less, LessEqual, Spaceship,
|
DoubleEqual, BangEqual, Greater, GreaterEqual, Less, LessEqual, Spaceship,
|
||||||
|
|
|
@ -11,10 +11,18 @@ pub type Rational = num_rational::Ratio<i64>;
|
||||||
pub type Complex = num_complex::Complex64;
|
pub type Complex = num_complex::Complex64;
|
||||||
|
|
||||||
static TYPE_COUNTER: AtomicUsize = AtomicUsize::new(Value::COUNT);
|
static TYPE_COUNTER: AtomicUsize = AtomicUsize::new(Value::COUNT);
|
||||||
#[derive(Clone, Debug, Eq)]
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum TypeData {
|
||||||
|
None,
|
||||||
|
StructFields(Rc<Vec<String>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Type {
|
pub struct Type {
|
||||||
pub name: Rc<str>,
|
pub name: Rc<str>,
|
||||||
pub id: usize
|
pub id: usize,
|
||||||
|
pub typedata: TypeData
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Type {
|
impl PartialEq for Type {
|
||||||
|
@ -23,11 +31,13 @@ impl PartialEq for Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for Type {}
|
||||||
|
|
||||||
pub fn generate_type(name: Rc<str>) -> Type {
|
pub fn generate_struct_type(name: Rc<str>, fields: Vec<String>) -> Type {
|
||||||
Type {
|
Type {
|
||||||
name,
|
name,
|
||||||
id: TYPE_COUNTER.fetch_add(1, atomic::Ordering::Relaxed)
|
id: TYPE_COUNTER.fetch_add(1, atomic::Ordering::Relaxed),
|
||||||
|
typedata: TypeData::StructFields(Rc::new(fields))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +47,7 @@ pub fn generate_builtin_types() -> Vec<Type> {
|
||||||
types.push(Type {
|
types.push(Type {
|
||||||
name: Rc::from(x.as_ref()),
|
name: Rc::from(x.as_ref()),
|
||||||
id: x as usize,
|
id: x as usize,
|
||||||
|
typedata: TypeData::None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
types
|
types
|
||||||
|
@ -112,7 +123,7 @@ fn repr_char(c: char) -> String {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CxprStruct {
|
pub struct CxprStruct {
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
pub data: Vec<Value>,
|
pub data: Rc<RefCell<HashMap<String, Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, EnumCount, EnumDiscriminants)]
|
#[derive(Clone, Debug, EnumCount, EnumDiscriminants)]
|
||||||
|
@ -128,7 +139,7 @@ pub enum Value {
|
||||||
List(Rc<RefCell<Vec<Value>>>),
|
List(Rc<RefCell<Vec<Value>>>),
|
||||||
Map(Rc<RefCell<HashMap<Value,Value>>>),
|
Map(Rc<RefCell<HashMap<Value,Value>>>),
|
||||||
Func(Func),
|
Func(Func),
|
||||||
Data(CxprStruct),
|
Struct(CxprStruct),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
@ -192,7 +203,10 @@ impl Value {
|
||||||
Some(name) => format!("<fn {}>", name),
|
Some(name) => format!("<fn {}>", name),
|
||||||
None => "<anonymous fn>".into(),
|
None => "<anonymous fn>".into(),
|
||||||
},
|
},
|
||||||
Self::Data(_) => todo!(),
|
Self::Struct(CxprStruct { ty, data })
|
||||||
|
=> format!("{} {{ {} }}", ty.name,
|
||||||
|
data.borrow().iter().map(|(k, v)| format!("{}: {}", k, v.repr()))
|
||||||
|
.collect::<Vec<String>>().join(", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,12 +290,13 @@ impl Value {
|
||||||
|
|
||||||
pub fn get_type(&self) -> Type {
|
pub fn get_type(&self) -> Type {
|
||||||
let discr = ValueDiscriminants::from(self);
|
let discr = ValueDiscriminants::from(self);
|
||||||
if let Self::Data(_) = self {
|
if let Self::Struct(_) = self {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
Type {
|
Type {
|
||||||
name: Rc::from(discr.as_ref()),
|
name: Rc::from(discr.as_ref()),
|
||||||
id: discr as usize
|
id: discr as usize,
|
||||||
|
typedata: TypeData::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,7 +351,7 @@ impl PartialEq for Value {
|
||||||
) => (*f1 as *const ()) == (*f2 as *const ()) && c1 == c2,
|
) => (*f1 as *const ()) == (*f2 as *const ()) && c1 == c2,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
(Self::Data(_), Self::Data(_)) => todo!("Can't compare data yet"),
|
(Self::Struct(_), Self::Struct(_)) => todo!("Can't compare data yet"),
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +414,7 @@ impl Hash for Value {
|
||||||
Self::List(l) => l.borrow().hash(state),
|
Self::List(l) => l.borrow().hash(state),
|
||||||
Self::Map(_) => todo!(),
|
Self::Map(_) => todo!(),
|
||||||
Self::Func(f) => f.hash(state),
|
Self::Func(f) => f.hash(state),
|
||||||
Self::Data(_) => todo!(),
|
Self::Struct(_) => todo!(),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue