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",
"env_logger",
"log",
"rand",
"stanza",
]
@ -231,6 +232,17 @@ dependencies = [
"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]]
name = "hashbrown"
version = "0.14.3"
@ -300,6 +312,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.79"
@ -327,6 +345,36 @@ dependencies = [
"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]]
name = "regex"
version = "1.10.3"
@ -453,6 +501,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "winapi"
version = "0.3.9"

View File

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

View File

@ -6,7 +6,7 @@ use std::{
use crate::{
abstract_tree::{Identifier, Type},
error::RwLockPoisonError,
value::{BuiltInFunction, BuiltInValue},
value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES},
Value,
};
@ -56,10 +56,19 @@ impl Context {
if self.inner.read()?.contains_key(identifier) {
Ok(true)
} else {
match identifier.as_str() {
"io" | "output" => Ok(true),
_ => Ok(false),
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)
}
}
@ -73,26 +82,38 @@ impl Context {
return Ok(Some(r#type.clone()));
}
let r#type = match identifier.as_str() {
"io" => BuiltInValue::Io.r#type(),
"output" => BuiltInFunction::Output.r#type(),
_ => return Ok(None),
};
for module in BUILT_IN_MODULES {
if identifier.as_str() == module.name() {
return Ok(Some(module.r#type()));
}
}
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> {
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
Ok(Some(value.clone()))
} else {
let value = match identifier.as_str() {
"io" => BuiltInValue::Io.value(),
"output" => Value::built_in_function(BuiltInFunction::Output),
_ => return Ok(None),
};
for module in BUILT_IN_MODULES {
if identifier.as_str() == module.name() {
return Ok(Some(module.value()));
}
}
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::ExpectedValue(_) => todo!(),
ValidationError::PropertyNotFound { .. } => todo!(),
ValidationError::WrongArguments { .. } => todo!(),
}
}
@ -273,6 +274,10 @@ pub enum ValidationError {
/// The position of the item that gave the "expected" type.
expected_position: SourcePosition,
},
WrongArguments {
expected: Vec<Type>,
actual: Vec<Type>,
},
VariableNotFound(Identifier),
PropertyNotFound {
identifier: Identifier,

View File

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

View File

@ -3,10 +3,12 @@ use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
io::stdin,
num::ParseIntError,
ops::Range,
sync::{Arc, OnceLock},
};
use rand::{thread_rng, Rng};
use stanza::{
renderer::{console::Console, Renderer},
style::{HAlign, MinWidth, Styles},
@ -16,7 +18,7 @@ use stanza::{
use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context,
error::RuntimeError,
error::{RuntimeError, ValidationError},
};
#[derive(Clone, Debug, PartialEq)]
@ -278,48 +280,104 @@ pub struct ParsedFunction {
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)]
pub enum BuiltInFunction {
Output,
IntParse,
IntRandomRange,
ReadLine,
WriteLine,
}
impl BuiltInFunction {
pub fn output() -> Value {
static OUTPUT: OnceLock<Value> = OnceLock::new();
OUTPUT
.get_or_init(|| Value::built_in_function(BuiltInFunction::Output))
.clone()
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::IntParse => "parse",
BuiltInFunction::IntRandomRange => "random_range",
BuiltInFunction::ReadLine => "read_line",
BuiltInFunction::WriteLine => "write_line",
}
}
pub fn read_line() -> Value {
static READ_LINE: OnceLock<Value> = OnceLock::new();
READ_LINE
.get_or_init(|| Value::built_in_function(BuiltInFunction::ReadLine))
.clone()
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))
}
}
.clone()
}
pub fn r#type(&self) -> Type {
match self {
BuiltInFunction::Output => Type::Function {
parameter_types: vec![Type::Any],
return_type: Box::new(Type::None),
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),
},
}
}
pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> {
match self {
BuiltInFunction::Output => {
println!("{}", arguments[0]);
BuiltInFunction::IntParse => {
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 => {
let mut input = String::new();
@ -328,6 +386,11 @@ impl BuiltInFunction {
Ok(Action::Return(Value::string(input)))
}
BuiltInFunction::WriteLine => {
println!("{}", arguments[0]);
Ok(Action::None)
}
}
}
}
@ -335,25 +398,59 @@ impl BuiltInFunction {
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
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::WriteLine => write!(f, "(to_output : any) : none {{ *MAGIC* }}"),
}
}
}
static INT: 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,
}
impl BuiltInValue {
impl BuiltInModule {
pub fn name(&self) -> &'static str {
match self {
BuiltInModule::Integer => "int",
BuiltInModule::Io => "io",
}
}
pub fn value(self) -> Value {
match self {
BuiltInValue::Io => {
BuiltInModule::Integer => {
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()
}
@ -361,8 +458,6 @@ impl BuiltInValue {
}
pub fn r#type(self) -> Type {
match self {
BuiltInValue::Io => Type::Map,
}
Type::Map
}
}