Continue standard library
This commit is contained in:
parent
a8f840a305
commit
eaff59c88d
@ -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()))
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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, .. } => {
|
||||
|
Loading…
Reference in New Issue
Block a user