use crate::ast::PrimitiveType;
use crate::lexer::Span;
use crate::semantics::types::{BuiltInSig, MethodSig, Symbol, SymbolKind, Type};
use lazy_static::lazy_static;
use phf::phf_map;
use std::collections::HashMap;
fn float() -> Type {
Type::Primitive(PrimitiveType::Float)
}
fn int() -> Type {
Type::Primitive(PrimitiveType::Int)
}
fn str_() -> Type {
Type::Primitive(PrimitiveType::Str)
}
fn bool_() -> Type {
Type::Primitive(PrimitiveType::Bool)
}
fn json_type() -> Type {
Type::Named("Json".to_string(), Vec::new())
}
fn sig(params: Vec<Type>, return_type: Type) -> BuiltInSig {
BuiltInSig {
params,
return_type,
}
}
fn register_batch(
m: &mut HashMap<&'static str, BuiltInSig>,
names: &[&'static str],
sig: BuiltInSig,
) {
for name in names {
m.insert(name, sig.clone());
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub enum ConstantValue {
Float(f64),
Int(i64),
Bool(bool),
}
#[derive(Debug, Clone, PartialEq)]
pub enum StdlibItem {
Function {
params: Vec<Type>,
ret: Type,
llvm_name: String,
},
Constant {
ty: Type,
value: ConstantValue,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum TypeDesc {
Float,
Int,
Bool,
Void,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ConstDesc {
Pi,
E,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum StdlibItemDesc {
Function {
params: &'static [TypeDesc],
ret: TypeDesc,
llvm_name: &'static str,
},
Constant {
ty: TypeDesc,
value: ConstDesc,
},
}
const EMPTY_PARAM_DESC: &[TypeDesc] = &[];
const INT_PARAM_DESC: &[TypeDesc] = &[TypeDesc::Int];
const INT_INT_PARAM_DESC: &[TypeDesc] = &[TypeDesc::Int, TypeDesc::Int];
fn materialize_type(desc: TypeDesc) -> Type {
match desc {
TypeDesc::Float => Type::Primitive(PrimitiveType::Float),
TypeDesc::Int => Type::Primitive(PrimitiveType::Int),
TypeDesc::Bool => Type::Primitive(PrimitiveType::Bool),
TypeDesc::Void => Type::Void,
}
}
fn materialize_const(desc: ConstDesc) -> ConstantValue {
match desc {
ConstDesc::Pi => ConstantValue::Float(std::f64::consts::PI),
ConstDesc::E => ConstantValue::Float(std::f64::consts::E),
}
}
fn materialize_stdlib_item(desc: &StdlibItemDesc) -> StdlibItem {
match desc {
StdlibItemDesc::Function {
params,
ret,
llvm_name,
} => StdlibItem::Function {
params: params.iter().copied().map(materialize_type).collect(),
ret: materialize_type(*ret),
llvm_name: (*llvm_name).to_string(),
},
StdlibItemDesc::Constant { ty, value } => StdlibItem::Constant {
ty: materialize_type(*ty),
value: materialize_const(*value),
},
}
}
static FLOAT_PARAM: &[Type] = &[Type::Primitive(PrimitiveType::Float)];
static FLOAT_FLOAT_PARAMS: &[Type] = &[
Type::Primitive(PrimitiveType::Float),
Type::Primitive(PrimitiveType::Float),
];
static INT_PARAM: &[Type] = &[Type::Primitive(PrimitiveType::Int)];
static INT_STR_PARAMS: &[Type] = &[
Type::Primitive(PrimitiveType::Int),
Type::Primitive(PrimitiveType::Str),
];
static BOOL_PARAM: &[Type] = &[Type::Primitive(PrimitiveType::Bool)];
static BOOL_STR_PARAMS: &[Type] = &[
Type::Primitive(PrimitiveType::Bool),
Type::Primitive(PrimitiveType::Str),
];
static STR_PARAM: &[Type] = &[Type::Primitive(PrimitiveType::Str)];
static STR_STR_PARAMS: &[Type] = &[
Type::Primitive(PrimitiveType::Str),
Type::Primitive(PrimitiveType::Str),
];
static EMPTY_PARAMS: &[Type] = &[];
lazy_static! {
static ref T_PARAM: Vec<Type> = vec![Type::Variable("T".to_string())];
static ref T_T_PARAMS: Vec<Type> = vec![
Type::Variable("T".to_string()),
Type::Variable("T".to_string())
];
static ref OPTIONAL_T_PARAM: Vec<Type> =
vec![Type::Optional(Box::new(Type::Variable("T".to_string())))];
static ref RESULT_T_E_PARAMS: Vec<Type> = vec![Type::Result(
Box::new(Type::Variable("T".to_string())),
Box::new(Type::Variable("E".to_string()))
)];
}
fn io_fn(name: &'static str, params: &'static [Type], ret: Type) -> StdlibItem {
StdlibItem::Function {
params: params.to_vec(),
ret,
llvm_name: name.to_string(),
}
}
fn io_str_fn(name: &'static str, ret: Type) -> StdlibItem {
io_fn(name, STR_PARAM, ret)
}
fn io_str_str_fn(name: &'static str, ret: Type) -> StdlibItem {
io_fn(name, STR_STR_PARAMS, ret)
}
fn io_result(ok: Type) -> Type {
Type::Result(Box::new(ok), Box::new(str_()))
}
fn net_bytes_type() -> Type {
Type::List(Box::new(Type::Primitive(PrimitiveType::Int)))
}
fn net_tuple_bytes_addr_type() -> Type {
Type::Tuple(Box::new(net_bytes_type()), Box::new(str_()))
}
fn tcp_stream_type() -> Type {
Type::Named("TcpStream".to_string(), Vec::new())
}
fn udp_socket_type() -> Type {
Type::Named("UdpSocket".to_string(), Vec::new())
}
fn tcp_listener_type() -> Type {
Type::Named("TcpListener".to_string(), Vec::new())
}
fn sql_connection_type() -> Type {
Type::Named("Connection".to_string(), Vec::new())
}
fn sql_transaction_type() -> Type {
Type::Named("Transaction".to_string(), Vec::new())
}
fn sql_result_set_type() -> Type {
Type::Named("ResultSet".to_string(), Vec::new())
}
fn sql_value_type() -> Type {
Type::Named("SqlValue".to_string(), Vec::new())
}
fn sql_row_type() -> Type {
Type::Map(Box::new(str_()), Box::new(sql_value_type()))
}
fn make_class_symbol(name: &str, methods: HashMap<String, MethodSig>, span: Span) -> Symbol {
Symbol {
kind: SymbolKind::Class,
span,
type_: Some(Type::Named(name.to_string(), Vec::new())),
interfaces: HashMap::new(),
methods,
fields: HashMap::new(),
type_params: Vec::new(),
original_name: None,
llvm_name: None,
default_param_count: 0,
variants: None,
}
}
fn make_import_module_symbol(module_name: &str, span: Span) -> Symbol {
Symbol {
kind: SymbolKind::Import,
span,
type_: Some(Type::Module(module_name.to_string())),
interfaces: HashMap::new(),
methods: HashMap::new(),
fields: HashMap::new(),
type_params: Vec::new(),
original_name: None,
llvm_name: None,
default_param_count: 0,
variants: None,
}
}
macro_rules! define_methods {
(
$($method_name:expr => {
params: [$($param:expr),* $(,)?],
return_type: $ret_type:expr,
is_static: $is_static:expr $(,)?
}),*
$(,)?
) => {
{
let mut methods = HashMap::new();
$(
methods.insert(
$method_name.to_string(),
MethodSig {
params: vec![$($param),*],
return_type: $ret_type,
is_static: $is_static,
},
);
)*
methods
}
};
}
macro_rules! insert_items {
(
$map:expr;
$($name:expr => $item_expr:expr),*
$(,)?
) => {
$(
$map.insert($name, $item_expr);
)*
};
}
fn tcp_stream_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"connect" => {
params: [str_()],
return_type: io_result(tcp_stream_type()),
is_static: true
},
"read" => {
params: [int()],
return_type: io_result(net_bytes_type()),
is_static: false
},
"write" => {
params: [net_bytes_type()],
return_type: io_result(int()),
is_static: false
}
};
insert_socket_common_methods(&mut methods);
methods
}
fn udp_socket_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"bind" => {
params: [str_()],
return_type: io_result(udp_socket_type()),
is_static: true
},
"send_to" => {
params: [net_bytes_type(), str_()],
return_type: io_result(int()),
is_static: false
},
"recv_from" => {
params: [int()],
return_type: io_result(net_tuple_bytes_addr_type()),
is_static: false
}
};
insert_socket_common_methods(&mut methods);
methods
}
fn insert_socket_common_methods(methods: &mut HashMap<String, MethodSig>) {
methods.extend(define_methods! {
"close" => {
params: [],
return_type: Type::Void,
is_static: false
},
"set_nonblocking" => {
params: [bool_()],
return_type: io_result(Type::Void),
is_static: false
},
"peer_addr" => {
params: [],
return_type: io_result(str_()),
is_static: false
},
"local_addr" => {
params: [],
return_type: io_result(str_()),
is_static: false
}
});
}
fn tcp_listener_methods() -> HashMap<String, MethodSig> {
define_methods! {
"bind" => {
params: [str_()],
return_type: io_result(tcp_listener_type()),
is_static: true
},
"accept" => {
params: [],
return_type: io_result(tcp_stream_type()),
is_static: false
},
"close" => {
params: [],
return_type: Type::Void,
is_static: false
},
"set_nonblocking" => {
params: [bool_()],
return_type: io_result(Type::Void),
is_static: false
},
"local_addr" => {
params: [],
return_type: io_result(str_()),
is_static: false
}
}
}
pub fn net_module_class_symbols(span: Span) -> HashMap<String, Symbol> {
let mut classes = HashMap::new();
classes.insert(
"TcpStream".to_string(),
make_class_symbol("TcpStream", tcp_stream_methods(), span),
);
classes.insert(
"UdpSocket".to_string(),
make_class_symbol("UdpSocket", udp_socket_methods(), span),
);
classes.insert(
"TcpListener".to_string(),
make_class_symbol("TcpListener", tcp_listener_methods(), span),
);
classes.insert(
"http".to_string(),
make_import_module_symbol("net.http", span),
);
classes
}
fn sql_connection_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"close" => {
params: [],
return_type: Type::Void,
is_static: false
},
"begin_transaction" => {
params: [],
return_type: io_result(sql_transaction_type()),
is_static: false
}
};
insert_sql_query_methods(&mut methods);
methods
}
fn sql_transaction_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"commit" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
},
"rollback" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
}
};
insert_sql_query_methods(&mut methods);
methods
}
fn insert_sql_query_methods(methods: &mut HashMap<String, MethodSig>) {
methods.extend(define_methods! {
"execute" => {
params: [str_()],
return_type: io_result(int()),
is_static: false
},
"execute_params" => {
params: [str_(), Type::List(Box::new(sql_value_type()))],
return_type: io_result(int()),
is_static: false
},
"query" => {
params: [str_()],
return_type: io_result(sql_result_set_type()),
is_static: false
},
"query_params" => {
params: [str_(), Type::List(Box::new(sql_value_type()))],
return_type: io_result(sql_result_set_type()),
is_static: false
}
});
}
fn sql_result_set_methods() -> HashMap<String, MethodSig> {
define_methods! {
"rows" => {
params: [],
return_type: Type::List(Box::new(sql_row_type())),
is_static: false
},
"next" => {
params: [],
return_type: Type::Optional(Box::new(sql_row_type())),
is_static: false
},
"columns" => {
params: [],
return_type: Type::List(Box::new(str_())),
is_static: false
}
}
}
fn sql_value_methods() -> HashMap<String, MethodSig> {
define_methods! {
"is_null" => {
params: [],
return_type: bool_(),
is_static: false
},
"as_bool" => {
params: [],
return_type: io_result(bool_()),
is_static: false
},
"as_int" => {
params: [],
return_type: io_result(int()),
is_static: false
},
"as_float" => {
params: [],
return_type: io_result(float()),
is_static: false
},
"as_string" => {
params: [],
return_type: io_result(str_()),
is_static: false
},
"as_bytes" => {
params: [],
return_type: io_result(Type::List(Box::new(int()))),
is_static: false
},
"to_string" => {
params: [],
return_type: str_(),
is_static: false
}
}
}
pub fn sql_module_class_symbols(span: Span) -> HashMap<String, Symbol> {
let mut classes = HashMap::new();
classes.insert(
"Connection".to_string(),
make_class_symbol("Connection", sql_connection_methods(), span),
);
classes.insert(
"Transaction".to_string(),
make_class_symbol("Transaction", sql_transaction_methods(), span),
);
classes.insert(
"ResultSet".to_string(),
make_class_symbol("ResultSet", sql_result_set_methods(), span),
);
classes.insert(
"SqlValue".to_string(),
make_class_symbol("SqlValue", sql_value_methods(), span),
);
classes
}
fn thread_methods() -> HashMap<String, MethodSig> {
define_methods! {
"join" => {
params: [],
return_type: Type::Result(Box::new(Type::Void), Box::new(str_())),
is_static: false
},
"detach" => {
params: [],
return_type: Type::Result(Box::new(Type::Void), Box::new(str_())),
is_static: false
}
}
}
fn condvar_methods() -> HashMap<String, MethodSig> {
define_methods! {
"new" => {
params: [],
return_type: Type::Named("CondVar".to_string(), Vec::new()),
is_static: true
},
"wait" => {
params: [Type::Named("Mutex".to_string(), Vec::new())],
return_type: Type::Result(Box::new(Type::Void), Box::new(str_())),
is_static: false
},
"signal" => {
params: [],
return_type: Type::Result(Box::new(Type::Void), Box::new(str_())),
is_static: false
},
"broadcast" => {
params: [],
return_type: Type::Result(Box::new(Type::Void), Box::new(str_())),
is_static: false
}
}
}
fn rwlock_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"new" => {
params: [],
return_type: Type::Named("RwLock".to_string(), Vec::new()),
is_static: true
},
"read_lock" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
},
"write_lock" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
}
};
insert_sync_unlock_method(&mut methods);
methods
}
fn mutex_methods() -> HashMap<String, MethodSig> {
let mut methods = define_methods! {
"new" => {
params: [],
return_type: Type::Named("Mutex".to_string(), Vec::new()),
is_static: true
},
"lock" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
}
};
insert_sync_unlock_method(&mut methods);
methods
}
fn insert_sync_unlock_method(methods: &mut HashMap<String, MethodSig>) {
methods.extend(define_methods! {
"unlock" => {
params: [],
return_type: io_result(Type::Void),
is_static: false
}
});
}
pub fn sync_module_class_symbols(span: Span) -> HashMap<String, Symbol> {
let mut classes = HashMap::new();
classes.insert(
"Thread".to_string(),
make_class_symbol("Thread", thread_methods(), span),
);
classes.insert(
"CondVar".to_string(),
make_class_symbol("CondVar", condvar_methods(), span),
);
classes.insert(
"RwLock".to_string(),
make_class_symbol("RwLock", rwlock_methods(), span),
);
classes.insert(
"Mutex".to_string(),
make_class_symbol("Mutex", mutex_methods(), span),
);
classes
}
fn datetime_fn(name: &'static str, params: &'static [Type], ret: Type) -> StdlibItem {
io_fn(name, params, ret)
}
static STDLIB_ITEMS: phf::Map<&'static str, StdlibItemDesc> = phf_map! {
"math.pi" => StdlibItemDesc::Constant { ty: TypeDesc::Float, value: ConstDesc::Pi },
"math.e" => StdlibItemDesc::Constant { ty: TypeDesc::Float, value: ConstDesc::E },
"random.seed" => StdlibItemDesc::Function { params: INT_PARAM_DESC, ret: TypeDesc::Void, llvm_name: "mux_rand_init" },
"random.next_int" => StdlibItemDesc::Function { params: EMPTY_PARAM_DESC, ret: TypeDesc::Int, llvm_name: "mux_rand_int" },
"random.next_range" => StdlibItemDesc::Function { params: INT_INT_PARAM_DESC, ret: TypeDesc::Int, llvm_name: "mux_rand_range" },
"random.next_float" => StdlibItemDesc::Function { params: EMPTY_PARAM_DESC, ret: TypeDesc::Float, llvm_name: "mux_rand_float" },
"random.next_bool" => StdlibItemDesc::Function { params: EMPTY_PARAM_DESC, ret: TypeDesc::Bool, llvm_name: "mux_rand_bool" },
};
lazy_static! {
pub static ref IO_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
insert_items! {
m;
"io.read_file" => io_str_fn("mux_io_read_file", io_result(str_())),
"io.write_file" => io_str_str_fn("mux_io_write_file", io_result(Type::Void)),
"io.exists" => io_str_fn("mux_io_exists", io_result(bool_())),
"io.remove" => io_str_fn("mux_io_remove", io_result(Type::Void)),
"io.is_file" => io_str_fn("mux_io_is_file", io_result(bool_())),
"io.is_dir" => io_str_fn("mux_io_is_dir", io_result(bool_())),
"io.mkdir" => io_str_fn("mux_io_mkdir", io_result(Type::Void)),
"io.listdir" => io_str_fn("mux_io_listdir", io_result(Type::List(Box::new(Type::Primitive(PrimitiveType::Str))))),
"io.join" => io_str_str_fn("mux_io_join", io_result(str_())),
"io.basename" => io_str_fn("mux_io_basename", io_result(str_())),
"io.dirname" => io_str_fn("mux_io_dirname", io_result(str_()))
}
m
};
pub static ref MATH_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
fn make_math_fn(llvm_name: &'static str, params: &'static [Type]) -> StdlibItem {
StdlibItem::Function {
params: params.to_vec(),
ret: Type::Primitive(PrimitiveType::Float),
llvm_name: llvm_name.to_string(),
}
}
let mut m = HashMap::new();
insert_items! {
m;
"math.sqrt" => make_math_fn("mux_math_sqrt", FLOAT_PARAM),
"math.sin" => make_math_fn("mux_math_sin", FLOAT_PARAM),
"math.cos" => make_math_fn("mux_math_cos", FLOAT_PARAM),
"math.tan" => make_math_fn("mux_math_tan", FLOAT_PARAM),
"math.asin" => make_math_fn("mux_math_asin", FLOAT_PARAM),
"math.acos" => make_math_fn("mux_math_acos", FLOAT_PARAM),
"math.atan" => make_math_fn("mux_math_atan", FLOAT_PARAM),
"math.ln" => make_math_fn("mux_math_ln", FLOAT_PARAM),
"math.log2" => make_math_fn("mux_math_log2", FLOAT_PARAM),
"math.log10" => make_math_fn("mux_math_log10", FLOAT_PARAM),
"math.exp" => make_math_fn("mux_math_exp", FLOAT_PARAM),
"math.abs" => make_math_fn("mux_math_abs", FLOAT_PARAM),
"math.floor" => make_math_fn("mux_math_floor", FLOAT_PARAM),
"math.ceil" => make_math_fn("mux_math_ceil", FLOAT_PARAM),
"math.round" => make_math_fn("mux_math_round", FLOAT_PARAM),
"math.atan2" => make_math_fn("mux_math_atan2", FLOAT_FLOAT_PARAMS),
"math.log" => make_math_fn("mux_math_log", FLOAT_FLOAT_PARAMS),
"math.min" => make_math_fn("mux_math_min", FLOAT_FLOAT_PARAMS),
"math.max" => make_math_fn("mux_math_max", FLOAT_FLOAT_PARAMS),
"math.hypot" => make_math_fn("mux_math_hypot", FLOAT_FLOAT_PARAMS),
"math.pow" => make_math_fn("mux_math_pow", FLOAT_FLOAT_PARAMS)
}
m
};
pub static ref DATETIME_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
insert_items! {
m;
"datetime.now" => datetime_fn("mux_datetime_now", EMPTY_PARAMS, io_result(int())),
"datetime.now_millis" => datetime_fn("mux_datetime_now_millis", EMPTY_PARAMS, io_result(int())),
"datetime.year" => datetime_fn("mux_datetime_year", INT_PARAM, io_result(int())),
"datetime.month" => datetime_fn("mux_datetime_month", INT_PARAM, io_result(int())),
"datetime.day" => datetime_fn("mux_datetime_day", INT_PARAM, io_result(int())),
"datetime.hour" => datetime_fn("mux_datetime_hour", INT_PARAM, io_result(int())),
"datetime.minute" => datetime_fn("mux_datetime_minute", INT_PARAM, io_result(int())),
"datetime.second" => datetime_fn("mux_datetime_second", INT_PARAM, io_result(int())),
"datetime.weekday" => datetime_fn("mux_datetime_weekday", INT_PARAM, io_result(int())),
"datetime.format" => datetime_fn("mux_datetime_format", INT_STR_PARAMS, io_result(str_())),
"datetime.format_local" => datetime_fn("mux_datetime_format_local", INT_STR_PARAMS, io_result(str_())),
"datetime.sleep" => datetime_fn("mux_datetime_sleep", INT_PARAM, io_result(Type::Void)),
"datetime.sleep_millis" => datetime_fn("mux_datetime_sleep_millis", INT_PARAM, io_result(Type::Void))
}
m
};
pub static ref ASSERT_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
fn make_item(llvm_name: &'static str, params: &[Type]) -> StdlibItem {
StdlibItem::Function {
params: params.to_vec(),
ret: Type::Void,
llvm_name: llvm_name.to_string(),
}
}
let mut m = HashMap::new();
insert_items! {
m;
"assert.assert" => make_item("mux_assert_assert", BOOL_STR_PARAMS),
"assert.assert_eq" => make_item("mux_assert_eq", &T_T_PARAMS),
"assert.assert_ne" => make_item("mux_assert_ne", &T_T_PARAMS),
"assert.assert_true" => make_item("mux_assert_true", BOOL_PARAM),
"assert.assert_false" => make_item("mux_assert_false", BOOL_PARAM),
"assert.assert_some" => make_item("mux_assert_some", &OPTIONAL_T_PARAM),
"assert.assert_none" => make_item("mux_assert_none", &OPTIONAL_T_PARAM),
"assert.assert_ok" => make_item("mux_assert_ok", &RESULT_T_E_PARAMS),
"assert.assert_err" => make_item("mux_assert_err", &RESULT_T_E_PARAMS)
}
m
};
pub static ref SYNC_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
fn spawn_fn() -> StdlibItem {
StdlibItem::Function {
params: vec![Type::Function {
params: Vec::new(),
returns: Box::new(Type::Void),
default_count: 0,
}],
ret: Type::Result(
Box::new(Type::Named("Thread".to_string(), Vec::new())),
Box::new(str_()),
),
llvm_name: "mux_sync_spawn".to_string(),
}
}
fn sleep_fn() -> StdlibItem {
StdlibItem::Function {
params: INT_PARAM.to_vec(),
ret: Type::Void,
llvm_name: "mux_sync_sleep".to_string(),
}
}
let mut m = HashMap::new();
insert_items! {
m;
"sync.spawn" => spawn_fn(),
"sync.sleep" => sleep_fn()
}
m
};
pub static ref ENV_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
m.insert(
"env.get",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: Type::Optional(Box::new(str_())),
llvm_name: "mux_env_get".to_string(),
},
);
m
};
pub static ref NET_HTTP_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
m.insert(
"net.http.request",
StdlibItem::Function {
params: vec![json_type()],
ret: io_result(json_type()),
llvm_name: "mux_net_http_request".to_string(),
},
);
m.insert(
"net.http.read_request",
StdlibItem::Function {
params: vec![tcp_stream_type()],
ret: io_result(json_type()),
llvm_name: "mux_net_http_read_request".to_string(),
},
);
m.insert(
"net.http.write_response",
StdlibItem::Function {
params: vec![tcp_stream_type(), json_type()],
ret: io_result(Type::Void),
llvm_name: "mux_net_http_write_response".to_string(),
},
);
m
};
pub static ref DATA_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
m.insert(
"json.parse",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: Type::Result(Box::new(Type::Named("Json".to_string(), Vec::new())), Box::new(str_())),
llvm_name: "mux_json_parse".to_string(),
},
);
m.insert(
"json.from_map",
StdlibItem::Function {
params: vec![Type::Map(Box::new(str_()), Box::new(Type::Variable("T".to_string())))],
ret: Type::Result(Box::new(Type::Named("Json".to_string(), Vec::new())), Box::new(str_())),
llvm_name: "mux_json_from_map".to_string(),
},
);
m.insert(
"json.to_map",
StdlibItem::Function {
params: vec![Type::Named("Json".to_string(), Vec::new())],
ret: Type::Result(
Box::new(Type::Map(Box::new(str_()), Box::new(Type::Named("Json".to_string(), Vec::new())))),
Box::new(str_()),
),
llvm_name: "mux_json_to_map".to_string(),
},
);
m.insert(
"csv.parse",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: Type::Result(Box::new(Type::Named("Csv".to_string(), Vec::new())), Box::new(str_())),
llvm_name: "mux_csv_parse".to_string(),
},
);
m.insert(
"csv.parse_with_headers",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: Type::Result(Box::new(Type::Named("Csv".to_string(), Vec::new())), Box::new(str_())),
llvm_name: "mux_csv_parse_with_headers".to_string(),
},
);
m
};
pub static ref SQL_STDLIB_ITEMS: HashMap<&'static str, StdlibItem> = {
let mut m = HashMap::new();
m.insert(
"sql.connect",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: io_result(sql_connection_type()),
llvm_name: "mux_sql_connect".to_string(),
},
);
m.insert(
"sql.int",
StdlibItem::Function {
params: INT_PARAM.to_vec(),
ret: sql_value_type(),
llvm_name: "mux_sql_value_int".to_string(),
},
);
m.insert(
"sql.float",
StdlibItem::Function {
params: FLOAT_PARAM.to_vec(),
ret: sql_value_type(),
llvm_name: "mux_sql_value_float".to_string(),
},
);
m.insert(
"sql.bool",
StdlibItem::Function {
params: BOOL_PARAM.to_vec(),
ret: sql_value_type(),
llvm_name: "mux_sql_value_bool".to_string(),
},
);
m.insert(
"sql.string",
StdlibItem::Function {
params: STR_PARAM.to_vec(),
ret: sql_value_type(),
llvm_name: "mux_sql_value_string".to_string(),
},
);
m.insert(
"sql.bytes",
StdlibItem::Function {
params: vec![Type::List(Box::new(int()))],
ret: sql_value_type(),
llvm_name: "mux_sql_value_bytes".to_string(),
},
);
m.insert(
"sql.null",
StdlibItem::Function {
params: EMPTY_PARAMS.to_vec(),
ret: sql_value_type(),
llvm_name: "mux_sql_value_null".to_string(),
},
);
m
};
pub static ref BUILT_IN_FUNCTIONS: HashMap<&'static str, BuiltInSig> = {
let mut m = HashMap::new();
m.insert("int_to_string", sig(vec![int()], str_()));
m.insert("int_to_float", sig(vec![int()], float()));
register_batch(
&mut m,
&["int_add", "int_sub", "int_mul", "int_div", "int_rem"],
sig(vec![int(), int()], int()),
);
register_batch(
&mut m,
&["int_eq", "int_lt"],
sig(vec![int(), int()], bool_()),
);
m.insert("float_to_string", sig(vec![float()], str_()));
m.insert("float_to_int", sig(vec![float()], int()));
m.insert("float_add", sig(vec![float(), float()], float()));
m.insert("string_to_int", sig(vec![str_()], int()));
m.insert("string_to_float", sig(vec![str_()], float()));
m.insert("string_concat", sig(vec![str_(), str_()], str_()));
m.insert("string_length", sig(vec![str_()], int()));
m.insert("bool_to_string", sig(vec![bool_()], str_()));
m.insert("bool_to_int", sig(vec![bool_()], int()));
m.insert("print", sig(vec![str_()], Type::Void));
m.insert("read_line", sig(vec![], str_()));
m.insert(
"range",
sig(vec![int(), int()], Type::List(Box::new(int()))),
);
m.insert(
"some",
sig(
vec![Type::Variable("T".to_string())],
Type::Optional(Box::new(Type::Variable("T".to_string()))),
),
);
m.insert("none", sig(vec![], Type::Optional(Box::new(Type::Void))));
m.insert(
"ok",
sig(
vec![Type::Variable("T".to_string())],
Type::Result(
Box::new(Type::Variable("T".to_string())),
Box::new(Type::Variable("E".to_string())),
),
),
);
m.insert(
"err",
sig(
vec![Type::Variable("E".to_string())],
Type::Result(
Box::new(Type::Variable("T".to_string())),
Box::new(Type::Variable("E".to_string())),
),
),
);
m
};
}
pub fn all_stdlib_items() -> impl Iterator<Item = (String, StdlibItem)> {
STDLIB_ITEMS
.entries()
.map(|(key, item)| (key.to_string(), materialize_stdlib_item(item)))
.chain(
IO_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
MATH_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
DATETIME_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
ASSERT_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
SYNC_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
ENV_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
NET_HTTP_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
DATA_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
.chain(
SQL_STDLIB_ITEMS
.iter()
.map(|(k, v)| (k.to_string(), v.clone())),
)
}
pub fn lookup_stdlib_item(name: &str) -> Option<StdlibItem> {
if let Some(item) = STDLIB_ITEMS.get(name) {
return Some(materialize_stdlib_item(item));
}
IO_STDLIB_ITEMS
.get(name)
.cloned()
.or_else(|| MATH_STDLIB_ITEMS.get(name).cloned())
.or_else(|| DATETIME_STDLIB_ITEMS.get(name).cloned())
.or_else(|| ASSERT_STDLIB_ITEMS.get(name).cloned())
.or_else(|| SYNC_STDLIB_ITEMS.get(name).cloned())
.or_else(|| ENV_STDLIB_ITEMS.get(name).cloned())
.or_else(|| NET_HTTP_STDLIB_ITEMS.get(name).cloned())
.or_else(|| DATA_STDLIB_ITEMS.get(name).cloned())
.or_else(|| SQL_STDLIB_ITEMS.get(name).cloned())
}
pub fn stdlib_item_to_symbol(item: &StdlibItem, span: Span) -> Symbol {
match item {
StdlibItem::Function {
params,
ret,
llvm_name,
} => Symbol {
kind: SymbolKind::Function,
span,
type_: Some(Type::Function {
params: params.to_vec(),
returns: Box::new(ret.clone()),
default_count: 0,
}),
interfaces: std::collections::HashMap::new(),
methods: std::collections::HashMap::new(),
fields: std::collections::HashMap::new(),
type_params: Vec::new(),
original_name: None,
llvm_name: Some(llvm_name.to_string()),
default_param_count: 0,
variants: None,
},
StdlibItem::Constant { ty, .. } => Symbol {
kind: SymbolKind::Constant,
span,
type_: Some(ty.clone()),
interfaces: std::collections::HashMap::new(),
methods: std::collections::HashMap::new(),
fields: std::collections::HashMap::new(),
type_params: Vec::new(),
original_name: None,
llvm_name: None,
default_param_count: 0,
variants: None,
},
}
}