Begin standard library

This commit is contained in:
Jeff 2024-03-23 08:15:48 -04:00
parent cb56fd05cd
commit 9bb4e1b944
8 changed files with 154 additions and 277 deletions

View File

@ -20,8 +20,6 @@ impl MapIndex {
impl AbstractNode for MapIndex { impl AbstractNode for MapIndex {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
let left_type = self.left.node.expected_type(context)?;
if let ( if let (
Expression::Identifier(collection_identifier), Expression::Identifier(collection_identifier),
Expression::Identifier(index_identifier), Expression::Identifier(index_identifier),
@ -72,7 +70,7 @@ impl AbstractNode for MapIndex {
} }
Err(ValidationError::CannotIndexWith { Err(ValidationError::CannotIndexWith {
collection_type: left_type, collection_type: self.left.node.expected_type(context)?,
collection_position: self.left.position, collection_position: self.left.position,
index_type: self.right.node.expected_type(context)?, index_type: self.right.node.expected_type(context)?,
index_position: self.right.position, index_position: self.right.position,

View File

@ -84,7 +84,6 @@ impl AbstractTree {
(_, _) => Ordering::Equal, (_, _) => Ordering::Equal,
}); });
println!("{:?}", statements);
AbstractTree(statements) AbstractTree(statements)
} }

View File

@ -0,0 +1,123 @@
use core::fmt;
use std::{
fmt::{Display, Formatter},
io::stdin,
thread,
time::Duration,
};
use rand::{thread_rng, Rng};
use crate::{
abstract_tree::{Action, Type},
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,
}
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 as_value(self) -> Value {
Value::built_in_function(self)
}
pub fn call(&self, arguments: Vec<Value>, context: &Context) -> Result<Action, RuntimeError> {
match self {
BuiltInFunction::IntParse => {
let string = arguments.get(0).unwrap();
if let ValueInner::String(_string) = string.inner().as_ref() {
// let integer = string.parse();
todo!()
// Ok(Action::Return(Value::integer(integer)))
} else {
let mut actual = Vec::with_capacity(arguments.len());
for value in arguments {
let r#type = value.r#type(context)?;
actual.push(r#type);
}
Err(RuntimeError::ValidationFailure(
ValidationError::WrongArguments {
expected: vec![Type::String],
actual,
},
))
}
}
BuiltInFunction::IntRandomRange => {
let range = arguments.get(0).unwrap();
if let ValueInner::Range(range) = range.inner().as_ref() {
let random = thread_rng().gen_range(range.clone());
Ok(Action::Return(Value::integer(random)))
} else {
panic!("Built-in function cannot have a non-function type.")
}
}
BuiltInFunction::ReadLine => {
let mut input = String::new();
stdin().read_line(&mut input)?;
Ok(Action::Return(Value::string(input)))
}
BuiltInFunction::WriteLine => {
println!("{}", arguments[0]);
Ok(Action::None)
}
BuiltInFunction::Sleep => {
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64));
}
Ok(Action::None)
}
}
}
}
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* }}"),
}
}
}

View File

@ -6,7 +6,6 @@ use std::{
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
error::{RwLockPoisonError, ValidationError}, error::{RwLockPoisonError, ValidationError},
value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
Value, Value,
}; };
@ -60,18 +59,6 @@ impl Context {
if self.inner.read()?.contains_key(identifier) { if self.inner.read()?.contains_key(identifier) {
Ok(true) Ok(true)
} else { } else {
for module in BUILT_IN_MODULES {
if identifier.as_str() == module.name() {
return Ok(true);
}
}
for function in BUILT_IN_FUNCTIONS {
if identifier.as_str() == function.name() {
return Ok(true);
}
}
Ok(false) Ok(false)
} }
} }
@ -83,40 +70,16 @@ impl Context {
ValueData::Value(value) => value.r#type(self)?, ValueData::Value(value) => value.r#type(self)?,
}; };
return Ok(Some(r#type.clone())); Ok(Some(r#type.clone()))
} else {
Ok(None)
} }
for module in BUILT_IN_MODULES {
if identifier.as_str() == module.name() {
return Ok(Some(module.r#type()));
}
}
for function in BUILT_IN_MODULES {
if identifier.as_str() == function.name() {
return Ok(Some(function.r#type()));
}
}
Ok(None)
} }
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> { pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) { if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else { } else {
for module in BUILT_IN_MODULES {
if identifier.as_str() == module.name() {
return Ok(Some(module.value()));
}
}
for function in BUILT_IN_MODULES {
if identifier.as_str() == function.name() {
return Ok(Some(function.value()));
}
}
Ok(None) Ok(None)
} }
} }

View File

@ -1,10 +1,13 @@
pub mod abstract_tree; pub mod abstract_tree;
pub mod built_in_functions;
pub mod context; pub mod context;
pub mod error; pub mod error;
pub mod lexer; pub mod lexer;
pub mod parser; pub mod parser;
pub mod value; pub mod value;
use abstract_tree::Identifier;
use built_in_functions::BUILT_IN_FUNCTIONS;
use context::Context; use context::Context;
use error::Error; use error::Error;
use lexer::lex; use lexer::lex;
@ -13,8 +16,16 @@ pub use value::Value;
pub fn interpret(source: &str) -> Result<Option<Value>, Vec<Error>> { pub fn interpret(source: &str) -> Result<Option<Value>, Vec<Error>> {
let context = Context::new(); let context = Context::new();
for function in BUILT_IN_FUNCTIONS {
context
.set_value(Identifier::new(function.name()), function.as_value())
.unwrap();
}
let mut interpreter = Interpreter::new(context); let mut interpreter = Interpreter::new(context);
interpreter.run(include_str!("../../std/io.ds"))?;
interpreter.run(source) interpreter.run(source)
} }

View File

@ -2,14 +2,10 @@ use std::{
cmp::Ordering, cmp::Ordering,
collections::BTreeMap, collections::BTreeMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
io::stdin,
ops::Range, ops::Range,
sync::{Arc, OnceLock}, sync::Arc,
thread,
time::Duration,
}; };
use rand::{thread_rng, Rng};
use stanza::{ use stanza::{
renderer::{console::Console, Renderer}, renderer::{console::Console, Renderer},
style::{HAlign, MinWidth, Styles}, style::{HAlign, MinWidth, Styles},
@ -18,6 +14,7 @@ use stanza::{
use crate::{ use crate::{
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition}, abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition},
built_in_functions::BuiltInFunction,
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
}; };
@ -225,7 +222,9 @@ impl ValueInner {
.collect(), .collect(),
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) => built_in_function.r#type(), Function::BuiltIn(built_in_function) => {
(*built_in_function).as_value().r#type(context)?
}
}, },
ValueInner::Structure { name, .. } => { ValueInner::Structure { name, .. } => {
if let Some(r#type) = context.get_type(name)? { if let Some(r#type) = context.get_type(name)? {
@ -331,226 +330,3 @@ pub struct ParsedFunction {
return_type: WithPosition<Type>, return_type: WithPosition<Type>,
body: WithPosition<Block>, body: WithPosition<Block>,
} }
static INT_PARSE: OnceLock<Value> = OnceLock::new();
static INT_RANDOM_RANGE: OnceLock<Value> = OnceLock::new();
static READ_LINE: OnceLock<Value> = OnceLock::new();
static WRITE_LINE: OnceLock<Value> = OnceLock::new();
static SLEEP: OnceLock<Value> = OnceLock::new();
pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 5] = [
BuiltInFunction::IntParse,
BuiltInFunction::IntRandomRange,
BuiltInFunction::ReadLine,
BuiltInFunction::WriteLine,
BuiltInFunction::Sleep,
];
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
IntParse,
IntRandomRange,
ReadLine,
WriteLine,
Sleep,
}
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 value(&self) -> Value {
match self {
BuiltInFunction::IntParse => {
INT_PARSE.get_or_init(|| Value::built_in_function(BuiltInFunction::IntParse))
}
BuiltInFunction::IntRandomRange => INT_RANDOM_RANGE
.get_or_init(|| Value::built_in_function(BuiltInFunction::IntRandomRange)),
BuiltInFunction::ReadLine => {
READ_LINE.get_or_init(|| Value::built_in_function(BuiltInFunction::ReadLine))
}
BuiltInFunction::WriteLine => {
WRITE_LINE.get_or_init(|| Value::built_in_function(BuiltInFunction::WriteLine))
}
BuiltInFunction::Sleep => {
SLEEP.get_or_init(|| Value::built_in_function(BuiltInFunction::Sleep))
}
}
.clone()
}
pub fn r#type(&self) -> Type {
match self {
BuiltInFunction::IntParse => Type::Function {
parameter_types: vec![Type::String],
return_type: Box::new(Type::Integer),
},
BuiltInFunction::IntRandomRange => Type::Function {
parameter_types: vec![Type::Range],
return_type: Box::new(Type::Integer),
},
BuiltInFunction::ReadLine => Type::Function {
parameter_types: Vec::with_capacity(0),
return_type: Box::new(Type::String),
},
BuiltInFunction::WriteLine => Type::Function {
parameter_types: vec![Type::Any],
return_type: Box::new(Type::None),
},
BuiltInFunction::Sleep => Type::Function {
parameter_types: vec![Type::Integer],
return_type: Box::new(Type::None),
},
}
}
pub fn call(&self, arguments: Vec<Value>, context: &Context) -> Result<Action, RuntimeError> {
match self {
BuiltInFunction::IntParse => {
let string = arguments.get(0).unwrap();
if let ValueInner::String(_string) = string.inner().as_ref() {
// let integer = string.parse();
todo!()
// Ok(Action::Return(Value::integer(integer)))
} else {
let mut actual = Vec::with_capacity(arguments.len());
for value in arguments {
let r#type = value.r#type(context)?;
actual.push(r#type);
}
Err(RuntimeError::ValidationFailure(
ValidationError::WrongArguments {
expected: vec![Type::String],
actual,
},
))
}
}
BuiltInFunction::IntRandomRange => {
let range = arguments.get(0).unwrap();
if let ValueInner::Range(range) = range.inner().as_ref() {
let random = thread_rng().gen_range(range.clone());
Ok(Action::Return(Value::integer(random)))
} else {
panic!("Built-in function cannot have a non-function type.")
}
}
BuiltInFunction::ReadLine => {
let mut input = String::new();
stdin().read_line(&mut input)?;
Ok(Action::Return(Value::string(input)))
}
BuiltInFunction::WriteLine => {
println!("{}", arguments[0]);
Ok(Action::None)
}
BuiltInFunction::Sleep => {
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
thread::sleep(Duration::from_millis(*milliseconds as u64));
}
Ok(Action::None)
}
}
}
}
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* }}"),
}
}
}
static INT: OnceLock<Value> = OnceLock::new();
static IO: OnceLock<Value> = OnceLock::new();
static THREAD: OnceLock<Value> = OnceLock::new();
pub const BUILT_IN_MODULES: [BuiltInModule; 3] =
[BuiltInModule::Int, BuiltInModule::Io, BuiltInModule::Thread];
pub enum BuiltInModule {
Int,
Io,
Thread,
}
impl BuiltInModule {
pub fn name(&self) -> &'static str {
match self {
BuiltInModule::Int => "int",
BuiltInModule::Io => "io",
BuiltInModule::Thread => "thread",
}
}
pub fn value(self) -> Value {
match self {
BuiltInModule::Int => {
let mut properties = BTreeMap::new();
properties.insert(
Identifier::new("parse"),
Value::built_in_function(BuiltInFunction::IntParse),
);
properties.insert(
Identifier::new("random_range"),
Value::built_in_function(BuiltInFunction::IntRandomRange),
);
INT.get_or_init(|| Value::map(properties)).clone()
}
BuiltInModule::Io => {
let mut properties = BTreeMap::new();
properties.insert(
Identifier::new("read_line"),
Value::built_in_function(BuiltInFunction::ReadLine),
);
properties.insert(
Identifier::new("write_line"),
Value::built_in_function(BuiltInFunction::WriteLine),
);
IO.get_or_init(|| Value::map(properties)).clone()
}
BuiltInModule::Thread => {
let mut properties = BTreeMap::new();
properties.insert(
Identifier::new("sleep"),
Value::built_in_function(BuiltInFunction::Sleep),
);
THREAD.get_or_init(|| Value::map(properties)).clone()
}
}
}
pub fn r#type(self) -> Type {
Type::Map
}
}

View File

@ -10,7 +10,7 @@ use std::{
io::{stderr, Write}, io::{stderr, Write},
}; };
use dust_lang::{context::Context, Interpreter}; use dust_lang::{context::Context, interpret};
/// Command-line arguments to be parsed. /// Command-line arguments to be parsed.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -46,9 +46,7 @@ fn main() {
return run_shell(context); return run_shell(context);
}; };
let mut interpreter = Interpreter::new(context); let eval_result = interpret(&source);
let eval_result = interpreter.run(&source);
match eval_result { match eval_result {
Ok(value) => { Ok(value) => {

9
std/io.ds Normal file
View File

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