This commit is contained in:
TriMill 2022-09-22 08:58:59 -04:00
parent 53bef7b5ed
commit 350f775b6c
7 changed files with 154 additions and 62 deletions

View file

@ -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!()
} }
} }

View file

@ -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 {

View file

@ -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, "+="),

View file

@ -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()?;

View file

@ -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(),
}) })
} }

View file

@ -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,

View file

@ -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!(),
} }
} }