Expand modules and function built-ins
This commit is contained in:
parent
18b8fd6681
commit
b7ae0f1b52
54
Cargo.lock
generated
54
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
151
src/value.rs
151
src/value.rs
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user