Continue standard library

This commit is contained in:
Jeff 2024-03-23 09:35:24 -04:00
parent a8f840a305
commit eaff59c88d
8 changed files with 100 additions and 95 deletions

View File

@ -111,8 +111,6 @@ impl AbstractNode for MapIndex {
if let (ValueInner::Map(map), Expression::Identifier(identifier)) = if let (ValueInner::Map(map), Expression::Identifier(identifier)) =
(collection.inner().as_ref(), &self.right.node) (collection.inner().as_ref(), &self.right.node)
{ {
println!("{map:?} {identifier}");
let action = map let action = map
.get(identifier) .get(identifier)
.map(|value| Action::Return(value.clone())) .map(|value| Action::Return(value.clone()))

View File

@ -1,6 +1,7 @@
use std::{cmp::Ordering, collections::BTreeMap, ops::Range}; use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
use crate::{ use crate::{
built_in_functions::BuiltInFunction,
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
Value, Value,
@ -11,6 +12,7 @@ use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPosit
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueNode { pub enum ValueNode {
Boolean(bool), Boolean(bool),
BuiltInFunction(BuiltInFunction),
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<WithPosition<Expression>>), List(Vec<WithPosition<Expression>>),
@ -27,7 +29,7 @@ pub enum ValueNode {
name: Identifier, name: Identifier,
fields: Vec<(Identifier, WithPosition<Expression>)>, fields: Vec<(Identifier, WithPosition<Expression>)>,
}, },
Function { ParsedFunction {
parameters: Vec<(Identifier, WithPosition<Type>)>, parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>, return_type: WithPosition<Type>,
body: WithPosition<Block>, body: WithPosition<Block>,
@ -35,7 +37,7 @@ pub enum ValueNode {
} }
impl AbstractNode for ValueNode { impl AbstractNode for ValueNode {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
let r#type = match self { let r#type = match self {
ValueNode::Boolean(_) => Type::Boolean, ValueNode::Boolean(_) => Type::Boolean,
ValueNode::Float(_) => Type::Float, ValueNode::Float(_) => Type::Float,
@ -44,7 +46,7 @@ impl AbstractNode for ValueNode {
let mut item_types = Vec::with_capacity(items.len()); let mut item_types = Vec::with_capacity(items.len());
for expression in items { for expression in items {
item_types.push(expression.node.expected_type(_context)?); item_types.push(expression.node.expected_type(context)?);
} }
Type::ListExact(item_types) Type::ListExact(item_types)
@ -52,7 +54,7 @@ impl AbstractNode for ValueNode {
ValueNode::Map(_) => Type::Map, ValueNode::Map(_) => Type::Map,
ValueNode::Range(_) => Type::Range, ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String, ValueNode::String(_) => Type::String,
ValueNode::Function { ValueNode::ParsedFunction {
parameters, parameters,
return_type, return_type,
.. ..
@ -70,7 +72,7 @@ impl AbstractNode for ValueNode {
let mut types = Vec::with_capacity(expressions.len()); let mut types = Vec::with_capacity(expressions.len());
for (identifier, expression) in expressions { for (identifier, expression) in expressions {
let r#type = expression.node.expected_type(_context)?; let r#type = expression.node.expected_type(context)?;
types.push(( types.push((
identifier.clone(), identifier.clone(),
@ -86,6 +88,7 @@ impl AbstractNode for ValueNode {
fields: types, fields: types,
} }
} }
ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(),
}; };
Ok(r#type) Ok(r#type)
@ -108,7 +111,7 @@ impl AbstractNode for ValueNode {
} }
} }
if let ValueNode::Function { if let ValueNode::ParsedFunction {
parameters, parameters,
return_type, return_type,
body, body,
@ -141,30 +144,22 @@ impl AbstractNode for ValueNode {
fields: expressions, fields: expressions,
} = self } = self
{ {
let types = if let Some(r#type) = context.get_type(name)? { if let Type::Structure {
if let Type::Structure { name: _,
name: _, fields: types,
fields: types, } = name.expected_type(context)?
} = r#type {
{ for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
types let actual_type = expression.node.expected_type(context)?;
} else {
todo!() expected_type.node.check(&actual_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position,
expected_position: expected_type.position,
}
})?
} }
} else {
return Err(ValidationError::TypeNotFound(name.clone()));
};
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
let actual_type = expression.node.expected_type(context)?;
expected_type.node.check(&actual_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: expression.position,
expected_position: expected_type.position,
}
})?
} }
} }
@ -214,7 +209,7 @@ impl AbstractNode for ValueNode {
} }
ValueNode::Range(range) => Value::range(range), ValueNode::Range(range) => Value::range(range),
ValueNode::String(string) => Value::string(string), ValueNode::String(string) => Value::string(string),
ValueNode::Function { ValueNode::ParsedFunction {
parameters, parameters,
return_type, return_type,
body, body,
@ -240,6 +235,9 @@ impl AbstractNode for ValueNode {
Value::structure(name, fields) Value::structure(name, fields)
} }
ValueNode::BuiltInFunction(built_in_function) => {
Value::built_in_function(built_in_function)
}
}; };
Ok(Action::Return(value)) Ok(Action::Return(value))
@ -282,12 +280,12 @@ impl Ord for ValueNode {
(String(left), String(right)) => left.cmp(right), (String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater, (String(_), _) => Ordering::Greater,
( (
Function { ParsedFunction {
parameters: left_parameters, parameters: left_parameters,
return_type: left_return, return_type: left_return,
body: left_body, body: left_body,
}, },
Function { ParsedFunction {
parameters: right_parameters, parameters: right_parameters,
return_type: right_return, return_type: right_return,
body: right_body, body: right_body,
@ -307,7 +305,7 @@ impl Ord for ValueNode {
parameter_cmp parameter_cmp
} }
} }
(Function { .. }, _) => Ordering::Greater, (ParsedFunction { .. }, _) => Ordering::Greater,
( (
Structure { Structure {
name: left_name, name: left_name,
@ -327,6 +325,8 @@ impl Ord for ValueNode {
} }
} }
(Structure { .. }, _) => Ordering::Greater, (Structure { .. }, _) => Ordering::Greater,
(BuiltInFunction(_), BuiltInFunction(_)) => todo!(),
(BuiltInFunction(_), _) => todo!(),
} }
} }
} }

View File

@ -1,6 +1,5 @@
use core::fmt;
use std::{ use std::{
fmt::{Display, Formatter}, fmt::{self, Display, Formatter},
io::stdin, io::stdin,
thread, thread,
time::Duration, time::Duration,
@ -9,48 +8,46 @@ use std::{
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use crate::{ use crate::{
abstract_tree::{Action, Type}, abstract_tree::{Action, Identifier, Type, WithPosition},
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
value::ValueInner, value::ValueInner,
Value, Value,
}; };
pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 5] = [ #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
BuiltInFunction::IntParse, pub struct BuiltInFunction {
BuiltInFunction::IntRandomRange, name: WithPosition<Identifier>,
BuiltInFunction::ReadLine,
BuiltInFunction::WriteLine,
BuiltInFunction::Sleep,
];
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
IntParse,
IntRandomRange,
ReadLine,
WriteLine,
Sleep,
} }
impl BuiltInFunction { impl BuiltInFunction {
pub fn name(&self) -> &'static str { pub fn new(name: WithPosition<Identifier>) -> Self {
match self { Self { name }
BuiltInFunction::IntParse => "parse", }
BuiltInFunction::IntRandomRange => "random_range",
BuiltInFunction::ReadLine => "read_line", pub fn name(&self) -> &Identifier {
BuiltInFunction::WriteLine => "write_line", &self.name.node
BuiltInFunction::Sleep => "sleep",
}
} }
pub fn as_value(self) -> Value { pub fn as_value(self) -> Value {
Value::built_in_function(self) Value::built_in_function(self)
} }
pub fn r#type(&self) -> Type {
match self.name.node.as_str() {
"WRITE_LINE" => Type::Function {
parameter_types: vec![Type::String],
return_type: Box::new(Type::None),
},
_ => {
todo!()
}
}
}
pub fn call(&self, arguments: Vec<Value>, context: &Context) -> Result<Action, RuntimeError> { pub fn call(&self, arguments: Vec<Value>, context: &Context) -> Result<Action, RuntimeError> {
match self { match self.name.node.as_str() {
BuiltInFunction::IntParse => { "INT_PARSE" => {
let string = arguments.get(0).unwrap(); let string = arguments.get(0).unwrap();
if let ValueInner::String(_string) = string.inner().as_ref() { if let ValueInner::String(_string) = string.inner().as_ref() {
@ -76,7 +73,7 @@ impl BuiltInFunction {
)) ))
} }
} }
BuiltInFunction::IntRandomRange => { "INT_RANDOM_RANGE" => {
let range = arguments.get(0).unwrap(); let range = arguments.get(0).unwrap();
if let ValueInner::Range(range) = range.inner().as_ref() { if let ValueInner::Range(range) = range.inner().as_ref() {
@ -87,37 +84,34 @@ impl BuiltInFunction {
panic!("Built-in function cannot have a non-function type.") panic!("Built-in function cannot have a non-function type.")
} }
} }
BuiltInFunction::ReadLine => { "READ_LINE" => {
let mut input = String::new(); let mut input = String::new();
stdin().read_line(&mut input)?; stdin().read_line(&mut input)?;
Ok(Action::Return(Value::string(input))) Ok(Action::Return(Value::string(input)))
} }
BuiltInFunction::WriteLine => { "WRITE_LINE" => {
println!("{}", arguments[0]); println!("{}", arguments[0]);
Ok(Action::None) Ok(Action::None)
} }
BuiltInFunction::Sleep => { "SLEEP" => {
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() { if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64)); thread::sleep(Duration::from_millis(*milliseconds as u64));
} }
Ok(Action::None) Ok(Action::None)
} }
_ => {
todo!()
}
} }
} }
} }
impl Display for BuiltInFunction { impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { write!(f, "{}", self.name.node)
BuiltInFunction::IntParse => write!(f, "(input : int) : str {{ *MAGIC* }}"),
BuiltInFunction::IntRandomRange => write!(f, "(input: range) : int {{ *MAGIC* }}"),
BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"),
BuiltInFunction::WriteLine => write!(f, "(to_output : any) : none {{ *MAGIC* }}"),
BuiltInFunction::Sleep => write!(f, "(milliseconds : int) : none {{ *MAGIC* }}"),
}
} }
} }

View File

@ -5,7 +5,6 @@ use std::{
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
built_in_functions::BUILT_IN_FUNCTIONS,
error::{RwLockPoisonError, ValidationError}, error::{RwLockPoisonError, ValidationError},
Interpreter, Value, Interpreter, Value,
}; };
@ -14,22 +13,11 @@ static STD_CONTEXT: OnceLock<Context> = OnceLock::new();
pub fn std_context<'a>() -> &'a Context { pub fn std_context<'a>() -> &'a Context {
STD_CONTEXT.get_or_init(|| { STD_CONTEXT.get_or_init(|| {
let mut data = BTreeMap::new(); let context = Context::new();
for function in BUILT_IN_FUNCTIONS {
data.insert(
Identifier::new(function.name()),
ValueData::Value(function.as_value()),
);
}
let context = Context::with_data(data);
let mut interpreter = Interpreter::new(context.clone()); let mut interpreter = Interpreter::new(context.clone());
interpreter.run(include_str!("../../std/io.ds")).unwrap(); interpreter.run(include_str!("../../std/io.ds")).unwrap();
context.remove(&Identifier::new("write_line")).unwrap();
context context
}) })
} }

View File

@ -116,6 +116,7 @@ pub enum Control {
Comma, Comma,
DoubleColon, DoubleColon,
Colon, Colon,
Dollar,
Dot, Dot,
DoubleDot, DoubleDot,
Semicolon, Semicolon,
@ -127,6 +128,7 @@ impl Display for Control {
Control::Arrow => write!(f, "->"), Control::Arrow => write!(f, "->"),
Control::CurlyOpen => write!(f, "{{"), Control::CurlyOpen => write!(f, "{{"),
Control::CurlyClose => write!(f, "}}"), Control::CurlyClose => write!(f, "}}"),
Control::Dollar => write!(f, "$"),
Control::SquareOpen => write!(f, "["), Control::SquareOpen => write!(f, "["),
Control::SquareClose => write!(f, "]"), Control::SquareClose => write!(f, "]"),
Control::ParenOpen => write!(f, "("), Control::ParenOpen => write!(f, "("),
@ -252,6 +254,7 @@ pub fn lexer<'src>() -> impl Parser<
just(":").to(Control::Colon), just(":").to(Control::Colon),
just("..").to(Control::DoubleDot), just("..").to(Control::DoubleDot),
just(".").to(Control::Dot), just(".").to(Control::Dot),
just("$").to(Control::Dollar),
)) ))
.map(Token::Control); .map(Token::Control);

View File

@ -4,6 +4,7 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*};
use crate::{ use crate::{
abstract_tree::*, abstract_tree::*,
built_in_functions::BuiltInFunction,
error::Error, error::Error,
lexer::{Control, Keyword, Operator, Token}, lexer::{Control, Keyword, Operator, Token},
}; };
@ -212,7 +213,7 @@ pub fn parser<'src>() -> impl Parser<
.with_position(state.span()) .with_position(state.span())
}); });
let function = identifier let parsed_function = identifier
.clone() .clone()
.then(type_specification.clone()) .then(type_specification.clone())
.separated_by(just(Token::Control(Control::Comma))) .separated_by(just(Token::Control(Control::Comma)))
@ -224,7 +225,7 @@ pub fn parser<'src>() -> impl Parser<
.then(type_specification.clone()) .then(type_specification.clone())
.then(block.clone()) .then(block.clone())
.map_with(|((parameters, return_type), body), state| { .map_with(|((parameters, return_type), body), state| {
Expression::Value(ValueNode::Function { Expression::Value(ValueNode::ParsedFunction {
parameters, parameters,
return_type, return_type,
body: body.with_position(state.span()), body: body.with_position(state.span()),
@ -232,8 +233,16 @@ pub fn parser<'src>() -> impl Parser<
.with_position(state.span()) .with_position(state.span())
}); });
let built_in_function = just(Token::Control(Control::Dollar))
.ignore_then(positioned_identifier.clone())
.map_with(|identifier, state| {
Expression::Value(ValueNode::BuiltInFunction(BuiltInFunction::new(identifier)))
.with_position(state.span())
});
let atom = choice(( let atom = choice((
function.clone(), built_in_function.clone(),
parsed_function.clone(),
identifier_expression.clone(), identifier_expression.clone(),
basic_value.clone(), basic_value.clone(),
list.clone(), list.clone(),
@ -406,7 +415,8 @@ pub fn parser<'src>() -> impl Parser<
structure_instance, structure_instance,
range, range,
logic_math_indexes_and_function_calls, logic_math_indexes_and_function_calls,
function, parsed_function,
built_in_function,
list, list,
map, map,
basic_value, basic_value,
@ -522,6 +532,18 @@ mod tests {
use super::*; use super::*;
#[test]
fn built_in_function() {
assert_eq!(
parse(&lex("$READ_LINE").unwrap()).unwrap()[0].node,
Statement::Expression(Expression::Value(ValueNode::BuiltInFunction(
BuiltInFunction::new(
Identifier::new("READ_LINE".to_string()).with_position((1, 10))
)
)))
)
}
#[test] #[test]
fn async_block() { fn async_block() {
assert_eq!( assert_eq!(
@ -756,7 +778,7 @@ mod tests {
fn function() { fn function() {
assert_eq!( assert_eq!(
parse(&lex("(x: int) : int { x }").unwrap()).unwrap()[0].node, parse(&lex("(x: int) : int { x }").unwrap()).unwrap()[0].node,
Statement::Expression(Expression::Value(ValueNode::Function { Statement::Expression(Expression::Value(ValueNode::ParsedFunction {
parameters: vec![(Identifier::new("x"), Type::Integer.with_position((4, 7)))], parameters: vec![(Identifier::new("x"), Type::Integer.with_position((4, 7)))],
return_type: Type::Integer.with_position((11, 14)), return_type: Type::Integer.with_position((11, 14)),
body: Block::new(vec![Statement::Expression(Expression::Identifier( body: Block::new(vec![Statement::Expression(Expression::Identifier(

View File

@ -223,7 +223,7 @@ impl ValueInner {
return_type: Box::new(parsed_function.return_type.node.clone()), return_type: Box::new(parsed_function.return_type.node.clone()),
}, },
Function::BuiltIn(built_in_function) => { Function::BuiltIn(built_in_function) => {
(*built_in_function).as_value().r#type(context)? built_in_function.clone().as_value().r#type(context)?
} }
}, },
ValueInner::Structure { name, .. } => { ValueInner::Structure { name, .. } => {

View File

@ -1,9 +1,9 @@
io = { io = {
read_line = () : str { read_line = () : str {
read_line() $READ_LINE()
} }
write_line = (output: str) : none { write_line = (output: str) : none {
write_line(output) $WRITE_LINE(output)
} }
} }