Begin standard library
This commit is contained in:
parent
cb56fd05cd
commit
9bb4e1b944
@ -20,8 +20,6 @@ impl MapIndex {
|
||||
|
||||
impl AbstractNode for MapIndex {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||
let left_type = self.left.node.expected_type(context)?;
|
||||
|
||||
if let (
|
||||
Expression::Identifier(collection_identifier),
|
||||
Expression::Identifier(index_identifier),
|
||||
@ -72,7 +70,7 @@ impl AbstractNode for MapIndex {
|
||||
}
|
||||
|
||||
Err(ValidationError::CannotIndexWith {
|
||||
collection_type: left_type,
|
||||
collection_type: self.left.node.expected_type(context)?,
|
||||
collection_position: self.left.position,
|
||||
index_type: self.right.node.expected_type(context)?,
|
||||
index_position: self.right.position,
|
||||
|
@ -84,7 +84,6 @@ impl AbstractTree {
|
||||
(_, _) => Ordering::Equal,
|
||||
});
|
||||
|
||||
println!("{:?}", statements);
|
||||
AbstractTree(statements)
|
||||
}
|
||||
|
||||
|
123
dust-lang/src/built_in_functions.rs
Normal file
123
dust-lang/src/built_in_functions.rs
Normal 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* }}"),
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ use std::{
|
||||
use crate::{
|
||||
abstract_tree::{Identifier, Type},
|
||||
error::{RwLockPoisonError, ValidationError},
|
||||
value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
|
||||
Value,
|
||||
};
|
||||
|
||||
@ -60,18 +59,6 @@ impl Context {
|
||||
if self.inner.read()?.contains_key(identifier) {
|
||||
Ok(true)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
@ -83,40 +70,16 @@ impl Context {
|
||||
ValueData::Value(value) => value.r#type(self)?,
|
||||
};
|
||||
|
||||
return Ok(Some(r#type.clone()));
|
||||
}
|
||||
|
||||
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(Some(r#type.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
|
||||
Ok(Some(value.clone()))
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
pub mod abstract_tree;
|
||||
pub mod built_in_functions;
|
||||
pub mod context;
|
||||
pub mod error;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod value;
|
||||
|
||||
use abstract_tree::Identifier;
|
||||
use built_in_functions::BUILT_IN_FUNCTIONS;
|
||||
use context::Context;
|
||||
use error::Error;
|
||||
use lexer::lex;
|
||||
@ -13,8 +16,16 @@ pub use value::Value;
|
||||
|
||||
pub fn interpret(source: &str) -> Result<Option<Value>, Vec<Error>> {
|
||||
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);
|
||||
|
||||
interpreter.run(include_str!("../../std/io.ds"))?;
|
||||
interpreter.run(source)
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,10 @@ use std::{
|
||||
cmp::Ordering,
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
io::stdin,
|
||||
ops::Range,
|
||||
sync::{Arc, OnceLock},
|
||||
thread,
|
||||
time::Duration,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
use stanza::{
|
||||
renderer::{console::Console, Renderer},
|
||||
style::{HAlign, MinWidth, Styles},
|
||||
@ -18,6 +14,7 @@ use stanza::{
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition},
|
||||
built_in_functions::BuiltInFunction,
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
@ -225,7 +222,9 @@ impl ValueInner {
|
||||
.collect(),
|
||||
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, .. } => {
|
||||
if let Some(r#type) = context.get_type(name)? {
|
||||
@ -331,226 +330,3 @@ pub struct ParsedFunction {
|
||||
return_type: WithPosition<Type>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::{
|
||||
io::{stderr, Write},
|
||||
};
|
||||
|
||||
use dust_lang::{context::Context, Interpreter};
|
||||
use dust_lang::{context::Context, interpret};
|
||||
|
||||
/// Command-line arguments to be parsed.
|
||||
#[derive(Parser, Debug)]
|
||||
@ -46,9 +46,7 @@ fn main() {
|
||||
return run_shell(context);
|
||||
};
|
||||
|
||||
let mut interpreter = Interpreter::new(context);
|
||||
|
||||
let eval_result = interpreter.run(&source);
|
||||
let eval_result = interpret(&source);
|
||||
|
||||
match eval_result {
|
||||
Ok(value) => {
|
||||
|
Loading…
Reference in New Issue
Block a user