1
0

Continue revising built-in functions

This commit is contained in:
Jeff 2024-04-21 18:06:26 -04:00
parent fb78798a1d
commit dbbb912b82
5 changed files with 77 additions and 40 deletions

View File

@ -1,17 +1,14 @@
use std::{
fmt::{self, Display, Formatter},
io::stdin,
thread,
time::Duration,
};
use std::{io::stdin, thread, time::Duration};
use crate::{
abstract_tree::{Action, Type},
context::Context,
error::RuntimeError,
error::{RuntimeError, ValidationError},
value::ValueInner,
Value,
};
use super::{AbstractNode, Expression, WithPosition};
use super::{AbstractNode, Expression};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunctionCall {
@ -21,15 +18,46 @@ pub enum BuiltInFunctionCall {
}
impl AbstractNode for BuiltInFunctionCall {
fn expected_type(&self, context: &Context) -> Result<Type, crate::error::ValidationError> {
todo!()
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self {
BuiltInFunctionCall::ReadLine => Ok(Type::String),
BuiltInFunctionCall::Sleep(_) => Ok(Type::None),
BuiltInFunctionCall::WriteLine(_) => Ok(Type::None),
}
}
fn validate(&self, context: &Context) -> Result<(), crate::error::ValidationError> {
todo!()
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
Ok(())
}
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
todo!()
match self {
BuiltInFunctionCall::ReadLine => {
let mut buffer = String::new();
stdin().read_line(&mut buffer)?;
Ok(Action::Return(Value::string(buffer)))
}
BuiltInFunctionCall::Sleep(expression) => {
let expression_run = expression.clone().run(context)?;
let expression_value = if let Action::Return(value) = expression_run {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position()),
));
};
if let ValueInner::Integer(milliseconds) = expression_value.inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64));
Ok(Action::None)
} else {
panic!("Expected an integer.");
}
}
BuiltInFunctionCall::WriteLine(_) => todo!(),
}
}
}

View File

@ -55,7 +55,9 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.expected_type(_context),
Expression::Math(math) => math.node.expected_type(_context),
Expression::Value(value_node) => value_node.node.expected_type(_context),
Expression::BuiltInFunctionCall(_) => todo!(),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.node.expected_type(_context)
}
}
}
@ -77,7 +79,9 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.validate(context),
Expression::Math(math) => math.node.validate(context),
Expression::Value(value_node) => value_node.node.validate(context),
Expression::BuiltInFunctionCall(_) => todo!(),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.node.validate(context)
}
}
}
@ -101,7 +105,9 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.run(_context),
Expression::Math(math) => math.node.run(_context),
Expression::Value(value_node) => value_node.node.run(_context),
Expression::BuiltInFunctionCall(_) => todo!(),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.node.run(_context)
}
}
}
}

View File

@ -255,22 +255,25 @@ pub fn parser<'src>(
},
);
let built_in_function_call = just(Token::Control(Control::DoubleUnderscore))
.ignore_then(choice((
just(Token::Keyword(Keyword::ReadLine)).to(BuiltInFunctionCall::ReadLine),
just(Token::Keyword(Keyword::Sleep))
.ignore_then(expression.clone())
.map(|expression| BuiltInFunctionCall::Sleep(expression)),
just(Token::Keyword(Keyword::WriteLine))
.ignore_then(expression.clone())
.map(|expression| BuiltInFunctionCall::WriteLine(expression)),
)))
.then_ignore(just(Token::Control(Control::DoubleUnderscore)))
.map_with(|built_in_function_call, state| {
Expression::BuiltInFunctionCall(
Box::new(built_in_function_call).with_position(state.span()),
)
});
let built_in_function_call = choice((
just(Token::Keyword(Keyword::ReadLine))
.ignore_then(just(Token::Control(Control::ParenOpen)))
.to(BuiltInFunctionCall::ReadLine),
just(Token::Keyword(Keyword::Sleep))
.ignore_then(just(Token::Control(Control::ParenOpen)))
.ignore_then(expression.clone())
.map(|expression| BuiltInFunctionCall::Sleep(expression)),
just(Token::Keyword(Keyword::WriteLine))
.ignore_then(just(Token::Control(Control::ParenOpen)))
.ignore_then(expression.clone())
.map(|expression| BuiltInFunctionCall::WriteLine(expression)),
))
.then_ignore(just(Token::Control(Control::ParenClose)))
.map_with(|built_in_function_call, state| {
Expression::BuiltInFunctionCall(
Box::new(built_in_function_call).with_position(state.span()),
)
});
let structure_field = identifier
.clone()
@ -600,19 +603,19 @@ mod tests {
#[test]
fn built_in_function() {
assert_eq!(
parse(&lex("__READ_LINE__").unwrap()).unwrap()[0],
parse(&lex("READ_LINE()").unwrap()).unwrap()[0],
Statement::Expression(Expression::BuiltInFunctionCall(
Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 13))
Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 11))
))
);
assert_eq!(
parse(&lex("__WRITE_LINE 'hiya'__").unwrap()).unwrap()[0],
parse(&lex("WRITE_LINE('hiya')").unwrap()).unwrap()[0],
Statement::Expression(Expression::BuiltInFunctionCall(
Box::new(BuiltInFunctionCall::WriteLine(Expression::Value(
ValueNode::String("hiya".to_string()).with_position((13, 19))
ValueNode::String("hiya".to_string()).with_position((11, 17))
)))
.with_position((0, 21))
.with_position((0, 18))
))
);
}

View File

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

View File

@ -1,5 +1,5 @@
thread = {
sleep = (milliseconds: int) none {
__SLEEP__(milliseconds)
SLEEP(milliseconds)
}
}