Expand modules and function built-ins

This commit is contained in:
Jeff 2024-03-18 08:15:30 -04:00
parent 18b8fd6681
commit b7ae0f1b52
6 changed files with 223 additions and 46 deletions

54
Cargo.lock generated
View File

@ -205,6 +205,7 @@ dependencies = [
"colored", "colored",
"env_logger", "env_logger",
"log", "log",
"rand",
"stanza", "stanza",
] ]
@ -231,6 +232,17 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.3" version = "0.14.3"
@ -300,6 +312,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.79" version = "1.0.79"
@ -327,6 +345,36 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.3" version = "1.10.3"
@ -453,6 +501,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@ -19,4 +19,5 @@ clap = { version = "4.5.2", features = ["derive"] }
colored = "2.1.0" colored = "2.1.0"
env_logger = "0.11.3" env_logger = "0.11.3"
log = "0.4.21" log = "0.4.21"
rand = "0.8.5"
stanza = "0.5.1" stanza = "0.5.1"

View File

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
error::RwLockPoisonError, error::RwLockPoisonError,
value::{BuiltInFunction, BuiltInValue}, value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
Value, Value,
}; };
@ -56,10 +56,19 @@ impl Context {
if self.inner.read()?.contains_key(identifier) { if self.inner.read()?.contains_key(identifier) {
Ok(true) Ok(true)
} else { } else {
match identifier.as_str() { for module in BUILT_IN_MODULES {
"io" | "output" => Ok(true), if identifier.as_str() == module.name() {
_ => Ok(false), return Ok(true);
}
} }
for function in BUILT_IN_FUNCTIONS {
if identifier.as_str() == function.name() {
return Ok(true);
}
}
Ok(false)
} }
} }
@ -73,26 +82,38 @@ impl Context {
return Ok(Some(r#type.clone())); return Ok(Some(r#type.clone()));
} }
let r#type = match identifier.as_str() { for module in BUILT_IN_MODULES {
"io" => BuiltInValue::Io.r#type(), if identifier.as_str() == module.name() {
"output" => BuiltInFunction::Output.r#type(), return Ok(Some(module.r#type()));
_ => return Ok(None), }
}; }
Ok(Some(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 {
let value = match identifier.as_str() { for module in BUILT_IN_MODULES {
"io" => BuiltInValue::Io.value(), if identifier.as_str() == module.name() {
"output" => Value::built_in_function(BuiltInFunction::Output), return Ok(Some(module.value()));
_ => return Ok(None), }
}; }
Ok(Some(value)) for function in BUILT_IN_MODULES {
if identifier.as_str() == function.name() {
return Ok(Some(function.value()));
}
}
Ok(None)
} }
} }

View File

@ -176,6 +176,7 @@ impl Error {
ValidationError::ExpectedFunction { .. } => todo!(), ValidationError::ExpectedFunction { .. } => todo!(),
ValidationError::ExpectedValue(_) => todo!(), ValidationError::ExpectedValue(_) => todo!(),
ValidationError::PropertyNotFound { .. } => todo!(), ValidationError::PropertyNotFound { .. } => todo!(),
ValidationError::WrongArguments { .. } => todo!(),
} }
} }
@ -273,6 +274,10 @@ pub enum ValidationError {
/// The position of the item that gave the "expected" type. /// The position of the item that gave the "expected" type.
expected_position: SourcePosition, expected_position: SourcePosition,
}, },
WrongArguments {
expected: Vec<Type>,
actual: Vec<Type>,
},
VariableNotFound(Identifier), VariableNotFound(Identifier),
PropertyNotFound { PropertyNotFound {
identifier: Identifier, identifier: Identifier,

View File

@ -1,6 +1,6 @@
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use chumsky::prelude::*; use chumsky::{prelude::*, text::whitespace};
use crate::error::Error; use crate::error::Error;
@ -228,10 +228,11 @@ pub fn lexer<'src>() -> impl Parser<
just("loop").padded(), just("loop").padded(),
just("while").padded(), just("while").padded(),
)) ))
.delimited_by(whitespace(), whitespace())
.map(Token::Keyword); .map(Token::Keyword);
choice(( choice((
boolean, float, integer, string, keyword, identifier, control, operator, boolean, float, integer, string, identifier, keyword, control, operator,
)) ))
.map_with(|token, state| (token, state.span())) .map_with(|token, state| (token, state.span()))
.padded() .padded()

View File

@ -3,10 +3,12 @@ use std::{
collections::BTreeMap, collections::BTreeMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
io::stdin, io::stdin,
num::ParseIntError,
ops::Range, ops::Range,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
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},
@ -16,7 +18,7 @@ use stanza::{
use crate::{ use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition}, abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context, context::Context,
error::RuntimeError, error::{RuntimeError, ValidationError},
}; };
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -278,48 +280,104 @@ pub struct ParsedFunction {
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();
pub const BUILT_IN_FUNCTIONS: [BuiltInFunction; 4] = [
BuiltInFunction::IntParse,
BuiltInFunction::IntRandomRange,
BuiltInFunction::ReadLine,
BuiltInFunction::WriteLine,
];
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction { pub enum BuiltInFunction {
Output, IntParse,
IntRandomRange,
ReadLine, ReadLine,
WriteLine,
} }
impl BuiltInFunction { impl BuiltInFunction {
pub fn output() -> Value { pub fn name(&self) -> &'static str {
static OUTPUT: OnceLock<Value> = OnceLock::new(); match self {
BuiltInFunction::IntParse => "parse",
OUTPUT BuiltInFunction::IntRandomRange => "random_range",
.get_or_init(|| Value::built_in_function(BuiltInFunction::Output)) BuiltInFunction::ReadLine => "read_line",
.clone() BuiltInFunction::WriteLine => "write_line",
}
} }
pub fn read_line() -> Value { pub fn value(&self) -> Value {
static READ_LINE: OnceLock<Value> = OnceLock::new(); match self {
BuiltInFunction::IntParse => {
READ_LINE INT_PARSE.get_or_init(|| Value::built_in_function(BuiltInFunction::IntParse))
.get_or_init(|| Value::built_in_function(BuiltInFunction::ReadLine)) }
.clone() 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))
}
}
.clone()
} }
pub fn r#type(&self) -> Type { pub fn r#type(&self) -> Type {
match self { match self {
BuiltInFunction::Output => Type::Function { BuiltInFunction::IntParse => Type::Function {
parameter_types: vec![Type::Any], parameter_types: vec![Type::String],
return_type: Box::new(Type::None), 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 { BuiltInFunction::ReadLine => Type::Function {
parameter_types: Vec::with_capacity(0), parameter_types: Vec::with_capacity(0),
return_type: Box::new(Type::String), return_type: Box::new(Type::String),
}, },
BuiltInFunction::WriteLine => Type::Function {
parameter_types: vec![Type::Any],
return_type: Box::new(Type::None),
},
} }
} }
pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> { pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> {
match self { match self {
BuiltInFunction::Output => { BuiltInFunction::IntParse => {
println!("{}", arguments[0]); let string = arguments.get(0).unwrap();
Ok(Action::None) if let ValueInner::String(string) = string.inner().as_ref() {
// let integer = string.parse();
todo!()
// Ok(Action::Return(Value::integer(integer)))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::WrongArguments {
expected: vec![Type::String],
actual: arguments.iter().map(|value| value.r#type()).collect(),
},
))
}
}
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 => { BuiltInFunction::ReadLine => {
let mut input = String::new(); let mut input = String::new();
@ -328,6 +386,11 @@ impl BuiltInFunction {
Ok(Action::Return(Value::string(input))) Ok(Action::Return(Value::string(input)))
} }
BuiltInFunction::WriteLine => {
println!("{}", arguments[0]);
Ok(Action::None)
}
} }
} }
} }
@ -335,25 +398,59 @@ impl BuiltInFunction {
impl Display for BuiltInFunction { impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
BuiltInFunction::Output => write!(f, "(to_output : any) : none {{ *MAGIC* }}"), BuiltInFunction::IntParse => write!(f, "(input : int) : str {{ *MAGIC* }}"),
BuiltInFunction::IntRandomRange => write!(f, "(input: range) : int {{ *MAGIC* }}"),
BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"), BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"),
BuiltInFunction::WriteLine => write!(f, "(to_output : any) : none {{ *MAGIC* }}"),
} }
} }
} }
static INT: OnceLock<Value> = OnceLock::new();
static IO: OnceLock<Value> = OnceLock::new(); static IO: OnceLock<Value> = OnceLock::new();
pub enum BuiltInValue { pub const BUILT_IN_MODULES: [BuiltInModule; 2] = [BuiltInModule::Integer, BuiltInModule::Io];
pub enum BuiltInModule {
Integer,
Io, Io,
} }
impl BuiltInValue { impl BuiltInModule {
pub fn name(&self) -> &'static str {
match self {
BuiltInModule::Integer => "int",
BuiltInModule::Io => "io",
}
}
pub fn value(self) -> Value { pub fn value(self) -> Value {
match self { match self {
BuiltInValue::Io => { BuiltInModule::Integer => {
let mut properties = BTreeMap::new(); let mut properties = BTreeMap::new();
properties.insert(Identifier::new("read_line"), BuiltInFunction::read_line()); 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() IO.get_or_init(|| Value::map(properties)).clone()
} }
@ -361,8 +458,6 @@ impl BuiltInValue {
} }
pub fn r#type(self) -> Type { pub fn r#type(self) -> Type {
match self { Type::Map
BuiltInValue::Io => Type::Map,
}
} }
} }