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)) =
(collection.inner().as_ref(), &self.right.node)
{
println!("{map:?} {identifier}");
let action = map
.get(identifier)
.map(|value| Action::Return(value.clone()))

View File

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

View File

@ -1,6 +1,5 @@
use core::fmt;
use std::{
fmt::{Display, Formatter},
fmt::{self, Display, Formatter},
io::stdin,
thread,
time::Duration,
@ -9,48 +8,46 @@ use std::{
use rand::{thread_rng, Rng};
use crate::{
abstract_tree::{Action, Type},
abstract_tree::{Action, Identifier, Type, WithPosition},
context::Context,
error::{RuntimeError, ValidationError},
value::ValueInner,
Value,
};
pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 5] = [
BuiltInFunction::IntParse,
BuiltInFunction::IntRandomRange,
BuiltInFunction::ReadLine,
BuiltInFunction::WriteLine,
BuiltInFunction::Sleep,
];
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
IntParse,
IntRandomRange,
ReadLine,
WriteLine,
Sleep,
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct BuiltInFunction {
name: WithPosition<Identifier>,
}
impl BuiltInFunction {
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::IntParse => "parse",
BuiltInFunction::IntRandomRange => "random_range",
BuiltInFunction::ReadLine => "read_line",
BuiltInFunction::WriteLine => "write_line",
BuiltInFunction::Sleep => "sleep",
}
pub fn new(name: WithPosition<Identifier>) -> Self {
Self { name }
}
pub fn name(&self) -> &Identifier {
&self.name.node
}
pub fn as_value(self) -> Value {
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> {
match self {
BuiltInFunction::IntParse => {
match self.name.node.as_str() {
"INT_PARSE" => {
let string = arguments.get(0).unwrap();
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();
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.")
}
}
BuiltInFunction::ReadLine => {
"READ_LINE" => {
let mut input = String::new();
stdin().read_line(&mut input)?;
Ok(Action::Return(Value::string(input)))
}
BuiltInFunction::WriteLine => {
"WRITE_LINE" => {
println!("{}", arguments[0]);
Ok(Action::None)
}
BuiltInFunction::Sleep => {
"SLEEP" => {
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64));
}
Ok(Action::None)
}
_ => {
todo!()
}
}
}
}
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
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* }}"),
}
write!(f, "{}", self.name.node)
}
}

View File

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

View File

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

View File

@ -4,6 +4,7 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*};
use crate::{
abstract_tree::*,
built_in_functions::BuiltInFunction,
error::Error,
lexer::{Control, Keyword, Operator, Token},
};
@ -212,7 +213,7 @@ pub fn parser<'src>() -> impl Parser<
.with_position(state.span())
});
let function = identifier
let parsed_function = identifier
.clone()
.then(type_specification.clone())
.separated_by(just(Token::Control(Control::Comma)))
@ -224,7 +225,7 @@ pub fn parser<'src>() -> impl Parser<
.then(type_specification.clone())
.then(block.clone())
.map_with(|((parameters, return_type), body), state| {
Expression::Value(ValueNode::Function {
Expression::Value(ValueNode::ParsedFunction {
parameters,
return_type,
body: body.with_position(state.span()),
@ -232,8 +233,16 @@ pub fn parser<'src>() -> impl Parser<
.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((
function.clone(),
built_in_function.clone(),
parsed_function.clone(),
identifier_expression.clone(),
basic_value.clone(),
list.clone(),
@ -406,7 +415,8 @@ pub fn parser<'src>() -> impl Parser<
structure_instance,
range,
logic_math_indexes_and_function_calls,
function,
parsed_function,
built_in_function,
list,
map,
basic_value,
@ -522,6 +532,18 @@ mod tests {
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]
fn async_block() {
assert_eq!(
@ -756,7 +778,7 @@ mod tests {
fn function() {
assert_eq!(
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)))],
return_type: Type::Integer.with_position((11, 14)),
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()),
},
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, .. } => {

View File

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