wip: working on type resolution.
This commit is contained in:
parent
4e476626ed
commit
40717b6c78
47 changed files with 883 additions and 350 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -14,6 +14,7 @@
|
||||||
"defstruct",
|
"defstruct",
|
||||||
"defstructfield",
|
"defstructfield",
|
||||||
"defstructproperty",
|
"defstructproperty",
|
||||||
|
"defuseproperty",
|
||||||
"hashrocket",
|
"hashrocket",
|
||||||
"indoc",
|
"indoc",
|
||||||
"lexer",
|
"lexer",
|
||||||
|
|
|
@ -3,5 +3,5 @@ pub mod stack;
|
||||||
pub mod unique_vec;
|
pub mod unique_vec;
|
||||||
|
|
||||||
pub use indexed_vec::{IndexedVec, IndexedVecKey};
|
pub use indexed_vec::{IndexedVec, IndexedVecKey};
|
||||||
pub use stack::Stack;
|
pub use stack::{Stack, StackError};
|
||||||
pub use unique_vec::{UniqueVec, UniqueVecKey};
|
pub use unique_vec::{UniqueVec, UniqueVecKey};
|
||||||
|
|
|
@ -25,16 +25,23 @@ impl<T> Stack<T> {
|
||||||
self.0.pop().ok_or(StackError::Underflow)
|
self.0.pop().ok_or(StackError::Underflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&self) -> Option<&T> {
|
pub fn peek(&self) -> Result<&T> {
|
||||||
self.0.last()
|
self.0.last().ok_or(StackError::Underflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_mut(&mut self) -> Option<&mut T> {
|
pub fn peek_mut(&mut self) -> Option<&mut T> {
|
||||||
self.0.last_mut()
|
self.0.last_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_slice(&self) -> &[T] {
|
pub fn iter(&self) -> std::slice::Iter<T> {
|
||||||
&self.0
|
self.0.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find<F>(&self, predicate: F) -> Option<&T>
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> bool,
|
||||||
|
{
|
||||||
|
self.0.iter().find(|t| predicate(*t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ pub enum NodeKind {
|
||||||
Struct,
|
Struct,
|
||||||
TypeName,
|
TypeName,
|
||||||
Unary,
|
Unary,
|
||||||
|
Use,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -161,4 +162,8 @@ pub enum NodeValue {
|
||||||
op: Operator,
|
op: Operator,
|
||||||
rhs: Box<Node>,
|
rhs: Box<Node>,
|
||||||
},
|
},
|
||||||
|
Use {
|
||||||
|
name: Box<Node>,
|
||||||
|
props: HashMap<String, Node>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ comment_block = @{ "###" ~ (!"###" ~ ANY)* ~ "###" }
|
||||||
comment_line = @{ "#" ~ (!("\r" | "\n") ~ ANY)* }
|
comment_line = @{ "#" ~ (!("\r" | "\n") ~ ANY)* }
|
||||||
documentation = @{ "```doc" ~ (!"```" ~ ANY)* ~ "```"}
|
documentation = @{ "```doc" ~ (!"```" ~ ANY)* ~ "```"}
|
||||||
|
|
||||||
module = _{ documentation? ~ (defstruct | defprotocol | defimpl) }
|
module = _{ documentation? ~ (defstruct | defprotocol | defimpl | defuse) }
|
||||||
|
|
||||||
defstruct = { "struct" ~ typename ~ defstructfields? ~ defstructproperties }
|
defstruct = { "struct" ~ typename ~ defstructfields? ~ defstructproperties }
|
||||||
defstructfields = { ("(" ~ (defstructfield ~ ("," ~ defstructfield)*)? ~ ")")? }
|
defstructfields = { ("(" ~ (defstructfield ~ ("," ~ defstructfield)*)? ~ ")")? }
|
||||||
|
@ -23,6 +23,10 @@ defimpl = { "impl" ~ typename ~ defimplproperties }
|
||||||
defimplproperties = { ("," ~ defimplproperty)* }
|
defimplproperties = { ("," ~ defimplproperty)* }
|
||||||
defimplproperty = { keyword ~ (typeblock | typeunion | typename) }
|
defimplproperty = { keyword ~ (typeblock | typeunion | typename) }
|
||||||
|
|
||||||
|
defuse = { "use" ~ typename ~ defuseproperties }
|
||||||
|
defuseproperties = { ("," ~ defuseproperty)* }
|
||||||
|
defuseproperty = { keyword ~ typename }
|
||||||
|
|
||||||
typeunion = { typename ~ ("+" ~ typename)+ }
|
typeunion = { typename ~ ("+" ~ typename)+ }
|
||||||
typeblock = { "do" ~ typeblockcontents* ~ "end" }
|
typeblock = { "do" ~ typeblockcontents* ~ "end" }
|
||||||
typeblockcontents = _{ documentation | alias | defp | defs | def }
|
typeblockcontents = _{ documentation | alias | defp | defs | def }
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub fn visit_pair(pair: Pair<'_, Rule>) -> Result<Node, Error> {
|
||||||
Rule::defprotocol => visit_protocol(pair),
|
Rule::defprotocol => visit_protocol(pair),
|
||||||
Rule::defs => visit_defs(pair),
|
Rule::defs => visit_defs(pair),
|
||||||
Rule::defstruct => visit_struct(pair),
|
Rule::defstruct => visit_struct(pair),
|
||||||
|
Rule::defuse => visit_use(pair),
|
||||||
Rule::documentation => Ok(Node::new(
|
Rule::documentation => Ok(Node::new(
|
||||||
NodeKind::Documentation,
|
NodeKind::Documentation,
|
||||||
NodeValue::Documentation(pair.as_str().to_string()),
|
NodeValue::Documentation(pair.as_str().to_string()),
|
||||||
|
@ -225,6 +226,37 @@ fn visit_struct_properties(pairs: Pairs<'_, Rule>) -> Result<HashMap<String, Nod
|
||||||
Ok(properties)
|
Ok(properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_use(pair: Pair<'_, Rule>) -> Result<Node, Error> {
|
||||||
|
assert_is_rule(&pair, Rule::defuse)?;
|
||||||
|
|
||||||
|
let span = pair.as_span();
|
||||||
|
let mut pairs = pair.into_inner();
|
||||||
|
|
||||||
|
let name = visit_typename(pairs.next().unwrap()).map(Box::new)?;
|
||||||
|
let props = visit_use_properties(pairs.next().unwrap().into_inner())?;
|
||||||
|
|
||||||
|
Ok(Node::new(
|
||||||
|
NodeKind::Use,
|
||||||
|
NodeValue::Use { name, props },
|
||||||
|
span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_use_properties(pairs: Pairs<'_, Rule>) -> Result<HashMap<String, Node>, Error> {
|
||||||
|
let mut properties = HashMap::new();
|
||||||
|
|
||||||
|
for prop in pairs {
|
||||||
|
assert_is_rule(&prop, Rule::defuseproperty)?;
|
||||||
|
|
||||||
|
let mut inner = prop.into_inner();
|
||||||
|
let key = keyword_to_string(inner.next().unwrap())?;
|
||||||
|
let value = visit_pair(inner.next().unwrap())?;
|
||||||
|
properties.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(properties)
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_typeblock(pair: Pair<'_, Rule>) -> Result<Node, Error> {
|
fn visit_typeblock(pair: Pair<'_, Rule>) -> Result<Node, Error> {
|
||||||
assert_is_rule(&pair, Rule::typeblock)?;
|
assert_is_rule(&pair, Rule::typeblock)?;
|
||||||
|
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
use super::{Error, Expression, Type, TypeVariable};
|
|
||||||
use crate::grammar::NodeKind;
|
|
||||||
use outrun_common::Stack;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Environment {
|
|
||||||
pub types: Stack<Arc<Type>>,
|
|
||||||
pub functions: Stack<Function>,
|
|
||||||
pub docs: Stack<String>,
|
|
||||||
type_id: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Environment {
|
|
||||||
pub fn find_concrete_type<T: ToString>(&self, name: T) -> Result<Arc<Type>, Error> {
|
|
||||||
let name = name.to_string();
|
|
||||||
|
|
||||||
self.types
|
|
||||||
.as_slice()
|
|
||||||
.iter()
|
|
||||||
.find(|t| t.to_string() == name)
|
|
||||||
.map(Clone::clone)
|
|
||||||
.ok_or(Error::UnknownType(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reference_type<T: ToString>(&mut self, name: T) -> Result<Arc<Type>, Error> {
|
|
||||||
self.find_concrete_type(name.to_string()).or_else(|_| {
|
|
||||||
let r#type = RefCell::new(TypeVariable::MaybeReference {
|
|
||||||
name: name.to_string(),
|
|
||||||
});
|
|
||||||
let r#type = Arc::new(Type::Variable { r#type });
|
|
||||||
self.types.push(r#type.clone());
|
|
||||||
Ok(r#type)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unbound_type(&mut self) -> Result<Arc<Type>, Error> {
|
|
||||||
let type_id = self.type_id;
|
|
||||||
self.type_id += 1;
|
|
||||||
let r#type = RefCell::new(TypeVariable::Unbound { id: type_id });
|
|
||||||
let r#type = Arc::new(Type::Variable { r#type });
|
|
||||||
self.types.push(r#type.clone());
|
|
||||||
Ok(r#type)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_function(&mut self) -> Result<&mut Function, Error> {
|
|
||||||
self.functions.peek_mut().ok_or(Error::NotAFunction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Environment {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut result = Environment {
|
|
||||||
types: Stack::new(),
|
|
||||||
functions: Stack::new(),
|
|
||||||
docs: Stack::new(),
|
|
||||||
type_id: 0,
|
|
||||||
};
|
|
||||||
result.types.push(Arc::new(Type::Atom));
|
|
||||||
result.types.push(Arc::new(Type::Boolean));
|
|
||||||
result.types.push(Arc::new(Type::Integer));
|
|
||||||
result.types.push(Arc::new(Type::Float));
|
|
||||||
result.types.push(Arc::new(Type::String));
|
|
||||||
result.types.push(Arc::new(Type::Array));
|
|
||||||
result.types.push(Arc::new(Type::Map));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Access {
|
|
||||||
Public,
|
|
||||||
Private,
|
|
||||||
Static,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
pub name: String,
|
|
||||||
pub arguments: Vec<String>,
|
|
||||||
pub r#type: Arc<Type>,
|
|
||||||
pub body: Vec<Expression>,
|
|
||||||
pub guards: Vec<Expression>,
|
|
||||||
pub access: Access,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
pub fn new<T: Into<Access>>(
|
|
||||||
name: String,
|
|
||||||
arguments: Vec<String>,
|
|
||||||
r#type: Arc<Type>,
|
|
||||||
access: T,
|
|
||||||
) -> Self {
|
|
||||||
Function {
|
|
||||||
name,
|
|
||||||
arguments,
|
|
||||||
r#type,
|
|
||||||
body: Vec::new(),
|
|
||||||
guards: Vec::new(),
|
|
||||||
access: access.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_body_expression(&mut self, expression: Expression) {
|
|
||||||
self.body.push(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_guard_expression(&mut self, expression: Expression) {
|
|
||||||
self.body.push(expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NodeKind> for Access {
|
|
||||||
fn from(node_kind: NodeKind) -> Access {
|
|
||||||
match node_kind {
|
|
||||||
NodeKind::DefPrivate => Access::Private,
|
|
||||||
NodeKind::DefStatic => Access::Static,
|
|
||||||
_ => Access::Public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::grammar::NodeKind;
|
use crate::grammar::NodeKind;
|
||||||
|
use outrun_common::StackError;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -9,4 +10,11 @@ pub enum Error {
|
||||||
UnknownType(String),
|
UnknownType(String),
|
||||||
MissingProperty(String),
|
MissingProperty(String),
|
||||||
NotAFunction,
|
NotAFunction,
|
||||||
|
StackError(StackError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StackError> for Error {
|
||||||
|
fn from(e: StackError) -> Self {
|
||||||
|
Error::StackError(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
48
outrun-compiler/src/ir/function.rs
Normal file
48
outrun-compiler/src/ir/function.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use super::{Expression, Type};
|
||||||
|
use crate::grammar::NodeKind;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Access {
|
||||||
|
Public,
|
||||||
|
Private,
|
||||||
|
Static,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Function {
|
||||||
|
pub name: String,
|
||||||
|
pub arguments: Vec<String>,
|
||||||
|
pub r#type: Arc<Type>,
|
||||||
|
pub body: Vec<Expression>,
|
||||||
|
pub guards: Vec<Expression>,
|
||||||
|
pub access: Access,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new<T: Into<Access>>(
|
||||||
|
name: String,
|
||||||
|
arguments: Vec<String>,
|
||||||
|
r#type: Arc<Type>,
|
||||||
|
access: T,
|
||||||
|
) -> Self {
|
||||||
|
Function {
|
||||||
|
name,
|
||||||
|
arguments,
|
||||||
|
r#type,
|
||||||
|
body: Vec::new(),
|
||||||
|
guards: Vec::new(),
|
||||||
|
access: access.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NodeKind> for Access {
|
||||||
|
fn from(node_kind: NodeKind) -> Access {
|
||||||
|
match node_kind {
|
||||||
|
NodeKind::DefPrivate => Access::Private,
|
||||||
|
NodeKind::DefStatic => Access::Static,
|
||||||
|
_ => Access::Public,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,20 @@
|
||||||
mod environment;
|
|
||||||
mod error;
|
mod error;
|
||||||
mod expression;
|
mod expression;
|
||||||
|
mod function;
|
||||||
|
mod module;
|
||||||
|
mod notice;
|
||||||
|
mod stages;
|
||||||
mod r#type;
|
mod r#type;
|
||||||
mod visitor;
|
mod visitor;
|
||||||
|
|
||||||
pub use environment::{Environment, Function};
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use expression::{Expression, ExpressionValue};
|
pub use expression::{Expression, ExpressionValue};
|
||||||
|
pub use function::Function;
|
||||||
|
pub use module::Module;
|
||||||
|
pub use notice::{Notice, NoticeKind, Severity};
|
||||||
pub use r#type::{Type, TypeVariable};
|
pub use r#type::{Type, TypeVariable};
|
||||||
|
|
||||||
pub use visitor::{visit_node, visit_nodes};
|
pub use visitor::{visit_node, visit_nodes};
|
||||||
|
|
||||||
|
pub fn improve(mut module: Module) -> Result<Module, Error> {
|
||||||
|
stages::link_type_references(module)
|
||||||
|
}
|
||||||
|
|
146
outrun-compiler/src/ir/module.rs
Normal file
146
outrun-compiler/src/ir/module.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
use super::{Error, Function, Notice, NoticeKind, Severity, Type, TypeVariable};
|
||||||
|
use crate::span::Span;
|
||||||
|
use outrun_common::Stack;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Module {
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
|
pub types: Stack<Arc<Type>>,
|
||||||
|
pub functions: Stack<Function>,
|
||||||
|
pub docs: Stack<String>,
|
||||||
|
pub notices: Vec<Notice>,
|
||||||
|
type_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn new(path: &Path) -> Module {
|
||||||
|
bootstrap(Module {
|
||||||
|
path: Some(path.to_owned()),
|
||||||
|
types: Stack::new(),
|
||||||
|
functions: Stack::new(),
|
||||||
|
docs: Stack::new(),
|
||||||
|
notices: Vec::new(),
|
||||||
|
type_id: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_named_type<T: ToString>(&self, name: T) -> Result<Arc<Type>, Error> {
|
||||||
|
let name = name.to_string();
|
||||||
|
|
||||||
|
self.types
|
||||||
|
.iter()
|
||||||
|
.find(|t| t.to_string() == name)
|
||||||
|
.map(Clone::clone)
|
||||||
|
.ok_or(Error::UnknownType(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reference_type<T: ToString>(
|
||||||
|
&mut self,
|
||||||
|
name: T,
|
||||||
|
span: Option<Span>,
|
||||||
|
) -> Result<Arc<Type>, Error> {
|
||||||
|
self.find_named_type(name.to_string()).or_else(|_| {
|
||||||
|
let r#type = RefCell::new(TypeVariable::Reference {
|
||||||
|
name: name.to_string(),
|
||||||
|
});
|
||||||
|
let r#type = Arc::new(Type::Variable { r#type, span });
|
||||||
|
self.types.push(r#type.clone())?;
|
||||||
|
Ok(r#type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unbound_type(&mut self) -> Result<Arc<Type>, Error> {
|
||||||
|
let type_id = self.type_id;
|
||||||
|
self.type_id += 1;
|
||||||
|
let r#type = RefCell::new(TypeVariable::Unbound { id: type_id });
|
||||||
|
let r#type = Arc::new(Type::Variable { r#type, span: None });
|
||||||
|
self.types.push(r#type.clone())?;
|
||||||
|
Ok(r#type)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn external_type<T: ToString>(&mut self, name: T, span: Span) -> Result<Arc<Type>, Error> {
|
||||||
|
let ty = Arc::new(Type::External {
|
||||||
|
name: name.to_string(),
|
||||||
|
span,
|
||||||
|
});
|
||||||
|
self.types.push(ty.clone())?;
|
||||||
|
Ok(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alias_type<T: ToString>(
|
||||||
|
&mut self,
|
||||||
|
name: T,
|
||||||
|
target: Arc<Type>,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Arc<Type>, Error> {
|
||||||
|
let ty = Arc::new(Type::Alias {
|
||||||
|
name: name.to_string(),
|
||||||
|
target,
|
||||||
|
span,
|
||||||
|
});
|
||||||
|
self.types.push(ty.clone())?;
|
||||||
|
Ok(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_function(&mut self) -> Result<&mut Function, Error> {
|
||||||
|
self.functions.peek_mut().ok_or(Error::NotAFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info(&mut self, span: Option<Span>, kind: NoticeKind) {
|
||||||
|
self.notices.push(Notice {
|
||||||
|
severity: Severity::Info,
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn warning(&mut self, span: Option<Span>, kind: NoticeKind) {
|
||||||
|
self.notices.push(Notice {
|
||||||
|
severity: Severity::Warning,
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&mut self, span: Option<Span>, kind: NoticeKind) {
|
||||||
|
self.notices.push(Notice {
|
||||||
|
severity: Severity::Error,
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search_type<F>(&self, predicate: F) -> Option<Arc<Type>>
|
||||||
|
where
|
||||||
|
F: Fn(Arc<Type>) -> bool,
|
||||||
|
{
|
||||||
|
self.types.find(|t| predicate((*t).clone())).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Module {
|
||||||
|
fn default() -> Self {
|
||||||
|
bootstrap(Module {
|
||||||
|
path: None,
|
||||||
|
types: Stack::new(),
|
||||||
|
functions: Stack::new(),
|
||||||
|
docs: Stack::new(),
|
||||||
|
notices: Vec::new(),
|
||||||
|
type_id: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bootstrap(mut module: Module) -> Module {
|
||||||
|
module.types.push(Arc::new(Type::Atom)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::Boolean)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::Integer)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::Float)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::String)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::Array)).unwrap();
|
||||||
|
module.types.push(Arc::new(Type::Map)).unwrap();
|
||||||
|
module
|
||||||
|
}
|
24
outrun-compiler/src/ir/notice.rs
Normal file
24
outrun-compiler/src/ir/notice.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::span::Span;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Severity {
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Notice {
|
||||||
|
pub severity: Severity,
|
||||||
|
pub kind: NoticeKind,
|
||||||
|
pub span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum NoticeKind {
|
||||||
|
UnexpectedFunctionProperty(String),
|
||||||
|
UnexpectedImplProperty(String),
|
||||||
|
UnexpectedProtocolProperty(String),
|
||||||
|
UnexpectedStructProperty(String),
|
||||||
|
CannotResolveType(String),
|
||||||
|
}
|
24
outrun-compiler/src/ir/stages.rs
Normal file
24
outrun-compiler/src/ir/stages.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use super::{Error, Module, NoticeKind, Type};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn link_type_references(mut module: Module) -> Result<Module, Error> {
|
||||||
|
let types: Vec<Arc<Type>> = module
|
||||||
|
.types
|
||||||
|
.iter()
|
||||||
|
.filter(|t| t.is_reference())
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for ty in types {
|
||||||
|
let target_name = ty.to_string();
|
||||||
|
let maybe_type = module.search_type(|ty| ty.is_linkable() && ty.to_string() == target_name);
|
||||||
|
|
||||||
|
if let Some(target) = maybe_type {
|
||||||
|
ty.link_to(target);
|
||||||
|
} else {
|
||||||
|
module.error(ty.span(), NoticeKind::CannotResolveType(target_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(module)
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::span::Span;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -8,21 +9,27 @@ pub enum Type {
|
||||||
documentation: Option<String>,
|
documentation: Option<String>,
|
||||||
name: String,
|
name: String,
|
||||||
fields: HashMap<String, Arc<Type>>,
|
fields: HashMap<String, Arc<Type>>,
|
||||||
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
Protocol {
|
Protocol {
|
||||||
documentation: Option<String>,
|
documentation: Option<String>,
|
||||||
name: String,
|
name: String,
|
||||||
requires: Option<Arc<Type>>,
|
requires: Option<Arc<Type>>,
|
||||||
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
Impl {
|
Impl {
|
||||||
documentation: Option<String>,
|
documentation: Option<String>,
|
||||||
protocol: Arc<Type>,
|
protocol: Arc<Type>,
|
||||||
augments: Arc<Type>,
|
augments: Arc<Type>,
|
||||||
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
Union(Vec<Arc<Type>>),
|
Union {
|
||||||
|
types: Vec<Arc<Type>>,
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
|
||||||
Atom,
|
Atom,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
@ -37,11 +44,82 @@ pub enum Type {
|
||||||
associated_type: Arc<Type>,
|
associated_type: Arc<Type>,
|
||||||
arguments: Vec<Arc<Type>>,
|
arguments: Vec<Arc<Type>>,
|
||||||
result: Arc<Type>,
|
result: Arc<Type>,
|
||||||
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
Variable {
|
Variable {
|
||||||
r#type: RefCell<TypeVariable>,
|
r#type: RefCell<TypeVariable>,
|
||||||
|
span: Option<Span>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
External {
|
||||||
|
name: String,
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
Alias {
|
||||||
|
name: String,
|
||||||
|
target: Arc<Type>,
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn is_protocol(&self) -> bool {
|
||||||
|
matches!(self, Type::Protocol { .. })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_named(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::Variable { r#type, .. } => r#type.borrow().is_named(),
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_reference(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::Variable { r#type, .. } => r#type.borrow().is_reference(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_linkable(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::Alias { target, .. } => target.is_linkable(),
|
||||||
|
Type::Array => true,
|
||||||
|
Type::Atom => true,
|
||||||
|
Type::Boolean => true,
|
||||||
|
Type::External { .. } => true,
|
||||||
|
Type::Float => true,
|
||||||
|
Type::Integer => true,
|
||||||
|
Type::Map => true,
|
||||||
|
Type::Protocol { .. } => true,
|
||||||
|
Type::Struct { .. } => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn span(&self) -> Option<Span> {
|
||||||
|
match self {
|
||||||
|
Type::Struct { span, .. } => Some(span.clone()),
|
||||||
|
Type::Protocol { span, .. } => Some(span.clone()),
|
||||||
|
Type::Impl { span, .. } => Some(span.clone()),
|
||||||
|
Type::Union { span, .. } => Some(span.clone()),
|
||||||
|
Type::Function { span, .. } => Some(span.clone()),
|
||||||
|
Type::Variable { span, .. } => span.clone(),
|
||||||
|
Type::External { span, .. } => Some(span.clone()),
|
||||||
|
Type::Alias { span, .. } => Some(span.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link_to(&self, target: Arc<Type>) {
|
||||||
|
match self {
|
||||||
|
Type::Variable { r#type, .. } => {
|
||||||
|
r#type.replace(TypeVariable::Link { r#type: target });
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Type {
|
impl ToString for Type {
|
||||||
|
@ -56,7 +134,7 @@ impl ToString for Type {
|
||||||
let augments_name = augments.to_string();
|
let augments_name = augments.to_string();
|
||||||
format!("Impl<{},{}>", protocol_name, augments_name)
|
format!("Impl<{},{}>", protocol_name, augments_name)
|
||||||
}
|
}
|
||||||
Type::Union(types) => {
|
Type::Union { types, .. } => {
|
||||||
let inner = types
|
let inner = types
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
|
@ -64,6 +142,8 @@ impl ToString for Type {
|
||||||
.join(",");
|
.join(",");
|
||||||
format!("Union<{}>", inner)
|
format!("Union<{}>", inner)
|
||||||
}
|
}
|
||||||
|
Type::External { name, .. } => name.clone(),
|
||||||
|
Type::Alias { name, .. } => name.clone(),
|
||||||
Type::Atom => "Outrun.Native.Atom".to_string(),
|
Type::Atom => "Outrun.Native.Atom".to_string(),
|
||||||
Type::Boolean => "Outrun.Native.Boolean".to_string(),
|
Type::Boolean => "Outrun.Native.Boolean".to_string(),
|
||||||
Type::Integer => "Outrun.Native.Integer".to_string(),
|
Type::Integer => "Outrun.Native.Integer".to_string(),
|
||||||
|
@ -86,7 +166,7 @@ impl ToString for Type {
|
||||||
.join(",");
|
.join(",");
|
||||||
format!("Function<{}, [{}] -> {}>", related, arguments, result)
|
format!("Function<{}, [{}] -> {}>", related, arguments, result)
|
||||||
}
|
}
|
||||||
Type::Variable { r#type } => r#type.borrow().to_string(),
|
Type::Variable { r#type, .. } => r#type.borrow().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,15 +174,29 @@ impl ToString for Type {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypeVariable {
|
pub enum TypeVariable {
|
||||||
Unbound { id: u64 },
|
Unbound { id: u64 },
|
||||||
MaybeReference { name: String },
|
Reference { name: String },
|
||||||
Link { r#type: Arc<Type> },
|
Link { r#type: Arc<Type> },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeVariable {
|
||||||
|
pub fn is_named(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeVariable::Reference { .. } => true,
|
||||||
|
TypeVariable::Link { r#type } => r#type.is_named(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_reference(&self) -> bool {
|
||||||
|
matches!(self, TypeVariable::Reference { .. })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToString for TypeVariable {
|
impl ToString for TypeVariable {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
TypeVariable::Unbound { id } => format!("T{}", id),
|
TypeVariable::Unbound { id } => format!("T{}", id),
|
||||||
TypeVariable::MaybeReference { name } => name.to_string(),
|
TypeVariable::Reference { name } => name.to_string(),
|
||||||
TypeVariable::Link { r#type } => r#type.to_string(),
|
TypeVariable::Link { r#type } => r#type.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,55 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Environment, Error, Expression, ExpressionValue, Function, Type};
|
use super::{Error, Expression, ExpressionValue, Function, Module, NoticeKind, Type};
|
||||||
use crate::grammar::{Node, NodeKind, NodeValue, Operator};
|
use crate::grammar::{Node, NodeKind, NodeValue, Operator};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn visit_nodes(mut env: Environment, mut nodes: Vec<Node>) -> Result<Environment, Error> {
|
pub fn visit_nodes(mut module: Module, mut nodes: Vec<Node>) -> Result<Module, Error> {
|
||||||
while let Some(node) = nodes.pop() {
|
while let Some(node) = nodes.pop() {
|
||||||
env = visit_node(env, node)?;
|
module = visit_node(module, node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(env)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visit_node(env: Environment, node: Node) -> Result<Environment, Error> {
|
pub fn visit_node(module: Module, node: Node) -> Result<Module, Error> {
|
||||||
consume_documentation(env.clone(), node.clone())
|
consume_documentation(module.clone(), node.clone())
|
||||||
.or_else(|_| consume_expression(env.clone(), node.clone()))
|
.or_else(|_| consume_expression(module.clone(), node.clone()))
|
||||||
.or_else(|_| consume_statement(env, node))
|
.or_else(|_| consume_statement(module, node))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_documentation(mut env: Environment, node: Node) -> Result<Environment, Error> {
|
fn consume_documentation(mut module: Module, node: Node) -> Result<Module, Error> {
|
||||||
assert_is_kind(&node, NodeKind::Documentation)?;
|
assert_is_kind(&node, NodeKind::Documentation)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Documentation(docs) => {
|
NodeValue::Documentation(docs) => {
|
||||||
println!("docs push: {:?}", docs);
|
println!("docs push: {:?}", docs);
|
||||||
env.docs.push(docs).unwrap();
|
module.docs.push(docs)?;
|
||||||
Ok(env)
|
Ok(module)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_expression(mut env: Environment, node: Node) -> Result<Environment, Error> {
|
fn consume_expression(module: Module, node: Node) -> Result<Module, Error> {
|
||||||
let (new_env, expression) = visit_expression(env, node)?;
|
let (mut module, expression) = visit_expression(module, node)?;
|
||||||
env = new_env;
|
module
|
||||||
env.current_function()
|
.current_function()
|
||||||
.map(|fun| fun.push_body_expression(expression))?;
|
.map(|fun| fun.body.push(expression))?;
|
||||||
|
|
||||||
Ok(env)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_statement(env: Environment, node: Node) -> Result<Environment, Error> {
|
fn consume_statement(module: Module, node: Node) -> Result<Module, Error> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
NodeKind::Block => visit_block(env, node),
|
NodeKind::Block => visit_block(module, node),
|
||||||
NodeKind::DefPrivate => visit_function_statement(env, node),
|
NodeKind::DefPrivate => visit_function_statement(module, node),
|
||||||
NodeKind::DefPublic => visit_function_statement(env, node),
|
NodeKind::DefPublic => visit_function_statement(module, node),
|
||||||
NodeKind::DefStatic => visit_function_statement(env, node),
|
NodeKind::DefStatic => visit_function_statement(module, node),
|
||||||
NodeKind::Impl => consume_type_statement(env, node),
|
NodeKind::Impl => consume_type_statement(module, node),
|
||||||
NodeKind::Protocol => consume_type_statement(env, node),
|
NodeKind::Protocol => consume_type_statement(module, node),
|
||||||
NodeKind::Struct => consume_type_statement(env, node),
|
NodeKind::Struct => consume_type_statement(module, node),
|
||||||
|
NodeKind::Use => visit_use_statement(module, node),
|
||||||
other => Err(Error::ExpectedReceived {
|
other => Err(Error::ExpectedReceived {
|
||||||
expected: vec![
|
expected: vec![
|
||||||
NodeKind::Block,
|
NodeKind::Block,
|
||||||
|
@ -65,27 +66,54 @@ fn consume_statement(env: Environment, node: Node) -> Result<Environment, Error>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_type_statement(env: Environment, node: Node) -> Result<Environment, Error> {
|
fn consume_type_statement(module: Module, node: Node) -> Result<Module, Error> {
|
||||||
let (env, _) = visit_type_statement(env, node)?;
|
let (module, _) = visit_type_statement(module, node)?;
|
||||||
Ok(env)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_type_union(env: Environment, node: Node) -> Result<(Environment, Arc<Type>), Error> {
|
fn eval_type_union(mut module: Module, node: Node) -> Result<(Module, Arc<Type>), Error> {
|
||||||
let (mut env, types) = eval_type_union_collect(env, &node)?;
|
match node.value {
|
||||||
|
NodeValue::TypeName(name) => {
|
||||||
|
if name == "Self" {
|
||||||
|
self_type(module)
|
||||||
|
} else if name.starts_with("Self.") {
|
||||||
|
let (mut module, parent) = self_type(module)?;
|
||||||
|
if parent.is_named() {
|
||||||
|
let name = parent.to_string();
|
||||||
|
let ty = module.reference_type(name, Some(node.span))?;
|
||||||
|
Ok((module, ty))
|
||||||
|
} else {
|
||||||
|
let inner = module.unbound_type()?;
|
||||||
|
let ty = module.alias_type(name, inner, node.span)?;
|
||||||
|
Ok((module, ty))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let ty = module.reference_type(name, Some(node.span))?;
|
||||||
|
Ok((module, ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeValue::Infix { .. } => {
|
||||||
|
let (mut module, types) = eval_type_union_collect(module, &node)?;
|
||||||
|
|
||||||
if types.len() == 1 {
|
if types.len() == 1 {
|
||||||
Ok((env, types[0].clone()))
|
Ok((module, types[0].clone()))
|
||||||
} else {
|
} else {
|
||||||
let ty = Arc::new(Type::Union(types));
|
let ty = Arc::new(Type::Union {
|
||||||
env.types.push(ty.clone()).unwrap();
|
types,
|
||||||
Ok((env, ty))
|
span: node.span,
|
||||||
|
});
|
||||||
|
module.types.push(ty.clone())?;
|
||||||
|
Ok((module, ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_type_union_collect(
|
fn eval_type_union_collect(
|
||||||
mut env: Environment,
|
mut module: Module,
|
||||||
node: &Node,
|
node: &Node,
|
||||||
) -> Result<(Environment, Vec<Arc<Type>>), Error> {
|
) -> Result<(Module, Vec<Arc<Type>>), Error> {
|
||||||
if !matches!(node.kind, NodeKind::Infix | NodeKind::TypeName) {
|
if !matches!(node.kind, NodeKind::Infix | NodeKind::TypeName) {
|
||||||
return Err(Error::ExpectedReceived {
|
return Err(Error::ExpectedReceived {
|
||||||
expected: vec![NodeKind::Infix, NodeKind::TypeName],
|
expected: vec![NodeKind::Infix, NodeKind::TypeName],
|
||||||
|
@ -99,41 +127,41 @@ fn eval_type_union_collect(
|
||||||
op: Operator::Plus,
|
op: Operator::Plus,
|
||||||
ref rhs,
|
ref rhs,
|
||||||
} => {
|
} => {
|
||||||
let (new_env, mut lhs) = eval_type_union_collect(env, lhs)?;
|
let (module, mut lhs) = eval_type_union_collect(module, lhs)?;
|
||||||
let (new_env, mut rhs) = eval_type_union_collect(new_env, rhs)?;
|
let (module, mut rhs) = eval_type_union_collect(module, rhs)?;
|
||||||
lhs.append(&mut rhs);
|
lhs.append(&mut rhs);
|
||||||
Ok((new_env, lhs))
|
Ok((module, lhs))
|
||||||
}
|
}
|
||||||
NodeValue::TypeName(name) => {
|
NodeValue::TypeName(name) => {
|
||||||
let ty = env.reference_type(name)?;
|
let ty = module.reference_type(name, Some(node.span))?;
|
||||||
Ok((env, vec![ty]))
|
Ok((module, vec![ty]))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block(env: Environment, node: Node) -> Result<Environment, Error> {
|
fn visit_block(module: Module, node: Node) -> Result<Module, Error> {
|
||||||
assert_is_kind(&node, NodeKind::Block)?;
|
assert_is_kind(&node, NodeKind::Block)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Block(block) => visit_nodes(env, block),
|
NodeValue::Block(block) => visit_nodes(module, block),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expression(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_expression(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
NodeKind::Array => visit_array(env, node),
|
NodeKind::Array => visit_array(module, node),
|
||||||
NodeKind::Atom => visit_atom(env, node),
|
NodeKind::Atom => visit_atom(module, node),
|
||||||
NodeKind::Boolean => visit_boolean(env, node),
|
NodeKind::Boolean => visit_boolean(module, node),
|
||||||
NodeKind::Constructor => visit_constructor(env, node),
|
NodeKind::Constructor => visit_constructor(module, node),
|
||||||
NodeKind::Float => visit_float(env, node),
|
NodeKind::Float => visit_float(module, node),
|
||||||
NodeKind::GetLocal => visit_get_local(env, node),
|
NodeKind::GetLocal => visit_get_local(module, node),
|
||||||
NodeKind::Integer => visit_integer(env, node),
|
NodeKind::Integer => visit_integer(module, node),
|
||||||
NodeKind::Let => visit_let_expression(env, node),
|
NodeKind::Let => visit_let_expression(module, node),
|
||||||
NodeKind::Map => visit_map(env, node),
|
NodeKind::Map => visit_map(module, node),
|
||||||
NodeKind::RemoteCall => visit_remote_call(env, node),
|
NodeKind::RemoteCall => visit_remote_call(module, node),
|
||||||
NodeKind::String => visit_string(env, node),
|
NodeKind::String => visit_string(module, node),
|
||||||
other => Err(Error::ExpectedReceived {
|
other => Err(Error::ExpectedReceived {
|
||||||
expected: vec![
|
expected: vec![
|
||||||
NodeKind::Array,
|
NodeKind::Array,
|
||||||
|
@ -153,23 +181,23 @@ fn visit_expression(env: Environment, node: Node) -> Result<(Environment, Expres
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_array(mut env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_array(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Array)?;
|
assert_is_kind(&node, NodeKind::Array)?;
|
||||||
|
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Array")?;
|
let r#type = module.find_named_type("Outrun.Native.Array")?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Array(nodes) => {
|
NodeValue::Array(nodes) => {
|
||||||
let mut array = Vec::new();
|
let mut array = Vec::new();
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let (new_env, expr) = visit_expression(env, node)?;
|
let (new_module, expr) = visit_expression(module, node)?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
array.push(expr);
|
array.push(expr);
|
||||||
}
|
}
|
||||||
let value = ExpressionValue::Array(array);
|
let value = ExpressionValue::Array(array);
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -181,14 +209,14 @@ fn visit_array(mut env: Environment, node: Node) -> Result<(Environment, Express
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_atom(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_atom(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Atom)?;
|
assert_is_kind(&node, NodeKind::Atom)?;
|
||||||
|
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Atom")?;
|
let r#type = module.find_named_type("Outrun.Native.Atom")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let value = node.value.into();
|
let value = node.value.into();
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -197,14 +225,14 @@ fn visit_atom(env: Environment, node: Node) -> Result<(Environment, Expression),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_boolean(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_boolean(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Boolean)?;
|
assert_is_kind(&node, NodeKind::Boolean)?;
|
||||||
|
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Boolean")?;
|
let r#type = module.find_named_type("Outrun.Native.Boolean")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let value = node.value.into();
|
let value = node.value.into();
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -213,26 +241,26 @@ fn visit_boolean(env: Environment, node: Node) -> Result<(Environment, Expressio
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constructor(mut env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_constructor(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Constructor)?;
|
assert_is_kind(&node, NodeKind::Constructor)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Constructor { name, fields } => {
|
NodeValue::Constructor { name, fields } => {
|
||||||
let name = typename_to_string(&name)?;
|
let name = typename_to_string(&name)?;
|
||||||
let r#type = env.reference_type(name)?;
|
let r#type = module.reference_type(name, Some(node.span))?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let mut value = Vec::new();
|
let mut value = Vec::new();
|
||||||
|
|
||||||
for field in fields.values() {
|
for field in fields.values() {
|
||||||
let (new_env, expression) = visit_expression(env, field.clone())?;
|
let (new_module, expression) = visit_expression(module, field.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
value.push(expression);
|
value.push(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = ExpressionValue::Array(value);
|
let value = ExpressionValue::Array(value);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -244,17 +272,17 @@ fn visit_constructor(mut env: Environment, node: Node) -> Result<(Environment, E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_float(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_float(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Float)?;
|
assert_is_kind(&node, NodeKind::Float)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Float(value) => {
|
NodeValue::Float(value) => {
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Float")?;
|
let r#type = module.find_named_type("Outrun.Native.Float")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let value = ExpressionValue::Float(value);
|
let value = ExpressionValue::Float(value);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -266,7 +294,7 @@ fn visit_float(env: Environment, node: Node) -> Result<(Environment, Expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_function_statement(mut env: Environment, node: Node) -> Result<Environment, Error> {
|
fn visit_function_statement(mut module: Module, node: Node) -> Result<Module, Error> {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
node.kind,
|
node.kind,
|
||||||
NodeKind::DefPublic | NodeKind::DefPrivate | NodeKind::DefStatic
|
NodeKind::DefPublic | NodeKind::DefPrivate | NodeKind::DefStatic
|
||||||
|
@ -288,52 +316,54 @@ fn visit_function_statement(mut env: Environment, node: Node) -> Result<Environm
|
||||||
props,
|
props,
|
||||||
result,
|
result,
|
||||||
} => {
|
} => {
|
||||||
let associated_type = env.types.peek().unwrap().clone();
|
let associated_type = module.types.peek().cloned()?;
|
||||||
|
let span = node.span;
|
||||||
|
|
||||||
let mut argument_names = Vec::new();
|
let mut argument_names = Vec::new();
|
||||||
let mut argument_types = Vec::new();
|
let mut argument_types = Vec::new();
|
||||||
|
|
||||||
for (key, value) in arguments {
|
for (key, value) in arguments {
|
||||||
argument_names.push(key);
|
argument_names.push(key);
|
||||||
let (new_env, ty) = eval_type_union(env, value)?;
|
|
||||||
env = new_env;
|
let (new_module, ty) = eval_type_union(module, value)?;
|
||||||
|
module = new_module;
|
||||||
argument_types.push(ty);
|
argument_types.push(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result_type = match result {
|
let result_type = match result {
|
||||||
Some(node) => {
|
Some(node) => {
|
||||||
let (new_env, result) = eval_type_union(env, *node)?;
|
let (new_module, result) = eval_type_union(module, *node)?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
None => env.unbound_type()?,
|
None => module.unbound_type()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let documentation = env.docs.pop().ok();
|
let documentation = module.docs.pop().ok();
|
||||||
|
println!("docs pop: {:?}", documentation);
|
||||||
|
|
||||||
let function_type = Arc::new(Type::Function {
|
let function_type = Arc::new(Type::Function {
|
||||||
associated_type,
|
associated_type,
|
||||||
arguments: argument_types,
|
arguments: argument_types,
|
||||||
result: result_type,
|
result: result_type,
|
||||||
documentation,
|
documentation,
|
||||||
|
span,
|
||||||
});
|
});
|
||||||
env.types.push(function_type.clone()).unwrap();
|
module.types.push(function_type.clone())?;
|
||||||
|
|
||||||
let function = Function::new(name, argument_names, function_type, node.kind);
|
let function = Function::new(name, argument_names, function_type, node.kind);
|
||||||
env.functions.push(function.clone()).unwrap();
|
module.functions.push(function.clone())?;
|
||||||
|
|
||||||
if let Some(guard) = props.get("when") {
|
if let Some(guard) = props.get("when") {
|
||||||
let (new_env, expr) = visit_expression(env, guard.clone())?;
|
let (new_module, expr) = visit_expression(module, guard.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
env.current_function()
|
module.current_function().map(|fun| fun.guards.push(expr))?;
|
||||||
.map(|fun| fun.push_guard_expression(expr))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(body) = props.get("as") {
|
if let Some(body) = props.get("as") {
|
||||||
let (new_env, expr) = visit_expression(env, body.clone())?;
|
let (new_module, expr) = visit_expression(module, body.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
env.current_function()
|
module.current_function().map(|fun| fun.body.push(expr))?
|
||||||
.map(|fun| fun.push_body_expression(expr))?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in props.keys() {
|
for key in props.keys() {
|
||||||
|
@ -344,23 +374,25 @@ fn visit_function_statement(mut env: Environment, node: Node) -> Result<Environm
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should really emit a warning...
|
module.warning(
|
||||||
eprintln!("Unexpected key {}", key);
|
Some(span),
|
||||||
|
NoticeKind::UnexpectedFunctionProperty(key.to_string()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(env)
|
Ok(module)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_get_local(mut env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_get_local(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::GetLocal)?;
|
assert_is_kind(&node, NodeKind::GetLocal)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::GetLocal(local) => {
|
NodeValue::GetLocal(local) => {
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let r#type = env.unbound_type()?;
|
let r#type = module.unbound_type()?;
|
||||||
let value = ExpressionValue::GetLocal(local);
|
let value = ExpressionValue::GetLocal(local);
|
||||||
let expr = Expression {
|
let expr = Expression {
|
||||||
r#type,
|
r#type,
|
||||||
|
@ -368,36 +400,41 @@ fn visit_get_local(mut env: Environment, node: Node) -> Result<(Environment, Exp
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((env, expr))
|
Ok((module, expr))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl(mut env: Environment, node: Node) -> Result<(Environment, Arc<Type>), Error> {
|
fn visit_impl(mut module: Module, node: Node) -> Result<(Module, Arc<Type>), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Impl)?;
|
assert_is_kind(&node, NodeKind::Impl)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Impl { name, props } => {
|
NodeValue::Impl { name, props } => {
|
||||||
let protocol = typename_to_string(&name).and_then(|name| env.reference_type(name))?;
|
let protocol = typename_to_string(&name)
|
||||||
|
.and_then(|name| module.reference_type(name, Some(node.span)))?;
|
||||||
let augments = props
|
let augments = props
|
||||||
.get("for")
|
.get("for")
|
||||||
.ok_or(Error::MissingProperty("for".to_string()))
|
.ok_or(Error::MissingProperty("for".to_string()))
|
||||||
.and_then(|node| typename_to_string(&node))
|
.and_then(|node| {
|
||||||
.and_then(|name| env.reference_type(name))?;
|
let name = typename_to_string(&node)?;
|
||||||
|
let ty = module.reference_type(name, Some(node.span))?;
|
||||||
|
Ok(ty)
|
||||||
|
})?;
|
||||||
|
|
||||||
let documentation = env.docs.pop().ok();
|
let documentation = module.docs.pop().ok();
|
||||||
|
|
||||||
let ty = Arc::new(Type::Impl {
|
let ty = Arc::new(Type::Impl {
|
||||||
protocol,
|
protocol,
|
||||||
augments,
|
augments,
|
||||||
documentation,
|
documentation,
|
||||||
|
span: node.span,
|
||||||
});
|
});
|
||||||
env.types.push(ty.clone()).unwrap();
|
module.types.push(ty.clone())?;
|
||||||
|
|
||||||
if let Some(node) = props.get("as") {
|
if let Some(node) = props.get("as") {
|
||||||
let new_env = consume_statement(env, node.clone())?;
|
let new_module = consume_statement(module, node.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in props.keys() {
|
for key in props.keys() {
|
||||||
|
@ -408,27 +445,29 @@ fn visit_impl(mut env: Environment, node: Node) -> Result<(Environment, Arc<Type
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should really emit a warning...
|
module.warning(
|
||||||
eprintln!("Unexpected key {}", key);
|
Some(node.span),
|
||||||
|
NoticeKind::UnexpectedImplProperty(key.to_string()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((env, ty))
|
Ok((module, ty))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_integer(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_integer(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Integer)?;
|
assert_is_kind(&node, NodeKind::Integer)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Integer(value) => {
|
NodeValue::Integer(value) => {
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Integer")?;
|
let r#type = module.find_named_type("Outrun.Native.Integer")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let value = ExpressionValue::Integer(value);
|
let value = ExpressionValue::Integer(value);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -440,10 +479,7 @@ fn visit_integer(env: Environment, node: Node) -> Result<(Environment, Expressio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_let_expression(
|
fn visit_let_expression(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
mut env: Environment,
|
|
||||||
node: Node,
|
|
||||||
) -> Result<(Environment, Expression), Error> {
|
|
||||||
assert_is_kind(&node, NodeKind::Let)?;
|
assert_is_kind(&node, NodeKind::Let)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
|
@ -456,14 +492,14 @@ fn visit_let_expression(
|
||||||
let expression_type;
|
let expression_type;
|
||||||
|
|
||||||
if let Some(ty) = r#type {
|
if let Some(ty) = r#type {
|
||||||
let (new_env, ty) = eval_type_union(env, *ty)?;
|
let (new_module, ty) = eval_type_union(module, *ty)?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
expression_type = ty;
|
expression_type = ty;
|
||||||
} else {
|
} else {
|
||||||
expression_type = env.unbound_type()?;
|
expression_type = module.unbound_type()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (new_env, value) = visit_expression(env, *value)?;
|
let (new_module, value) = visit_expression(module, *value)?;
|
||||||
|
|
||||||
let value = ExpressionValue::Let {
|
let value = ExpressionValue::Let {
|
||||||
name,
|
name,
|
||||||
|
@ -476,32 +512,32 @@ fn visit_let_expression(
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((new_env, expr))
|
Ok((new_module, expr))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map(mut env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_map(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Map)?;
|
assert_is_kind(&node, NodeKind::Map)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::Map(map) => {
|
NodeValue::Map(map) => {
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.Map")?;
|
let r#type = module.find_named_type("Outrun.Native.Map")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
|
|
||||||
for (key, value) in map {
|
for (key, value) in map {
|
||||||
let (new_env, key) = visit_expression(env, key)?;
|
let (new_module, key) = visit_expression(module, key)?;
|
||||||
let (new_env, value) = visit_expression(new_env, value)?;
|
let (new_module, value) = visit_expression(new_module, value)?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
values.push((key, value));
|
values.push((key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = ExpressionValue::Map(values);
|
let value = ExpressionValue::Map(values);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -513,7 +549,7 @@ fn visit_map(mut env: Environment, node: Node) -> Result<(Environment, Expressio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_protocol(mut env: Environment, node: Node) -> Result<(Environment, Arc<Type>), Error> {
|
fn visit_protocol(mut module: Module, node: Node) -> Result<(Module, Arc<Type>), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Protocol)?;
|
assert_is_kind(&node, NodeKind::Protocol)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
|
@ -523,21 +559,23 @@ fn visit_protocol(mut env: Environment, node: Node) -> Result<(Environment, Arc<
|
||||||
let mut requires = None;
|
let mut requires = None;
|
||||||
|
|
||||||
if let Some(union) = props.get("requires") {
|
if let Some(union) = props.get("requires") {
|
||||||
let (new_env, ty) = eval_type_union(env, union.clone())?;
|
let (new_module, ty) = eval_type_union(module, union.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
requires = Some(ty);
|
requires = Some(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let documentation = env.docs.pop().ok();
|
let documentation = module.docs.pop().ok();
|
||||||
|
println!("docs pop: {:?}", documentation);
|
||||||
|
|
||||||
let ty = Arc::new(Type::Protocol {
|
let ty = Arc::new(Type::Protocol {
|
||||||
name,
|
name,
|
||||||
requires,
|
requires,
|
||||||
documentation,
|
documentation,
|
||||||
|
span: node.span,
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(node) = props.get("as") {
|
if let Some(node) = props.get("as") {
|
||||||
env = consume_statement(env, node.clone())?;
|
module = consume_statement(module, node.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in props.keys() {
|
for key in props.keys() {
|
||||||
|
@ -548,17 +586,19 @@ fn visit_protocol(mut env: Environment, node: Node) -> Result<(Environment, Arc<
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should really emit a warning...
|
module.warning(
|
||||||
eprintln!("Unexpected key {}", key);
|
Some(node.span),
|
||||||
|
NoticeKind::UnexpectedProtocolProperty(key.to_string()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((env, ty))
|
Ok((module, ty))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_remote_call(mut env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_remote_call(mut module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::RemoteCall)?;
|
assert_is_kind(&node, NodeKind::RemoteCall)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
|
@ -568,15 +608,15 @@ fn visit_remote_call(mut env: Environment, node: Node) -> Result<(Environment, E
|
||||||
arguments,
|
arguments,
|
||||||
} => {
|
} => {
|
||||||
let ty = typename_to_string(&associated_type)?;
|
let ty = typename_to_string(&associated_type)?;
|
||||||
let ty = env.reference_type(ty)?;
|
let ty = module.reference_type(ty, Some(node.span))?;
|
||||||
|
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
let (new_env, arg) = visit_expression(env, argument)?;
|
let (new_module, arg) = visit_expression(module, argument)?;
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
env = new_env;
|
module = new_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = ExpressionValue::RemoteCall {
|
let value = ExpressionValue::RemoteCall {
|
||||||
|
@ -585,10 +625,10 @@ fn visit_remote_call(mut env: Environment, node: Node) -> Result<(Environment, E
|
||||||
arguments: args,
|
arguments: args,
|
||||||
};
|
};
|
||||||
|
|
||||||
let r#type = env.unbound_type()?;
|
let r#type = module.unbound_type()?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -600,17 +640,17 @@ fn visit_remote_call(mut env: Environment, node: Node) -> Result<(Environment, E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_string(env: Environment, node: Node) -> Result<(Environment, Expression), Error> {
|
fn visit_string(module: Module, node: Node) -> Result<(Module, Expression), Error> {
|
||||||
assert_is_kind(&node, NodeKind::String)?;
|
assert_is_kind(&node, NodeKind::String)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
NodeValue::String(ref string) => {
|
NodeValue::String(ref string) => {
|
||||||
let r#type = env.find_concrete_type("Outrun.Native.String")?;
|
let r#type = module.find_named_type("Outrun.Native.String")?;
|
||||||
let span = node.span;
|
let span = node.span;
|
||||||
let value = ExpressionValue::String(string.to_string());
|
let value = ExpressionValue::String(string.to_string());
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
env,
|
module,
|
||||||
Expression {
|
Expression {
|
||||||
r#type,
|
r#type,
|
||||||
span,
|
span,
|
||||||
|
@ -622,7 +662,7 @@ fn visit_string(env: Environment, node: Node) -> Result<(Environment, Expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_struct(mut env: Environment, node: Node) -> Result<(Environment, Arc<Type>), Error> {
|
fn visit_struct(mut module: Module, node: Node) -> Result<(Module, Arc<Type>), Error> {
|
||||||
assert_is_kind(&node, NodeKind::Struct)?;
|
assert_is_kind(&node, NodeKind::Struct)?;
|
||||||
|
|
||||||
match node.value {
|
match node.value {
|
||||||
|
@ -635,23 +675,25 @@ fn visit_struct(mut env: Environment, node: Node) -> Result<(Environment, Arc<Ty
|
||||||
let mut new_fields = HashMap::new();
|
let mut new_fields = HashMap::new();
|
||||||
|
|
||||||
for (key, value) in fields.iter() {
|
for (key, value) in fields.iter() {
|
||||||
let (new_env, value) = eval_type_union(env, value.clone())?;
|
let (new_module, value) = eval_type_union(module, value.clone())?;
|
||||||
env = new_env;
|
module = new_module;
|
||||||
new_fields.insert(key.clone(), value);
|
new_fields.insert(key.clone(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let documentation = env.docs.pop().ok();
|
let documentation = module.docs.pop().ok();
|
||||||
|
println!("docs pop: {:?}", documentation);
|
||||||
|
|
||||||
let r#type = Arc::new(Type::Struct {
|
let r#type = Arc::new(Type::Struct {
|
||||||
name,
|
name,
|
||||||
fields: new_fields,
|
fields: new_fields,
|
||||||
documentation,
|
documentation,
|
||||||
|
span: node.span,
|
||||||
});
|
});
|
||||||
|
|
||||||
env.types.push(r#type.clone()).unwrap();
|
module.types.push(r#type.clone())?;
|
||||||
|
|
||||||
if let Some(node) = props.get("as") {
|
if let Some(node) = props.get("as") {
|
||||||
env = consume_statement(env, node.clone())?;
|
module = consume_statement(module, node.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in props.keys() {
|
for key in props.keys() {
|
||||||
|
@ -662,21 +704,23 @@ fn visit_struct(mut env: Environment, node: Node) -> Result<(Environment, Arc<Ty
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should really emit a warning...
|
module.warning(
|
||||||
eprintln!("Unexpected key {}", key);
|
Some(node.span),
|
||||||
|
NoticeKind::UnexpectedStructProperty(key.to_string()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((env, r#type))
|
Ok((module, r#type))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_type_statement(env: Environment, node: Node) -> Result<(Environment, Arc<Type>), Error> {
|
fn visit_type_statement(module: Module, node: Node) -> Result<(Module, Arc<Type>), Error> {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
NodeKind::Struct => visit_struct(env, node),
|
NodeKind::Struct => visit_struct(module, node),
|
||||||
NodeKind::Protocol => visit_protocol(env, node),
|
NodeKind::Protocol => visit_protocol(module, node),
|
||||||
NodeKind::Impl => visit_impl(env, node),
|
NodeKind::Impl => visit_impl(module, node),
|
||||||
other => Err(Error::ExpectedReceived {
|
other => Err(Error::ExpectedReceived {
|
||||||
expected: vec![NodeKind::Struct, NodeKind::Protocol, NodeKind::Impl],
|
expected: vec![NodeKind::Struct, NodeKind::Protocol, NodeKind::Impl],
|
||||||
received: other.clone(),
|
received: other.clone(),
|
||||||
|
@ -684,6 +728,35 @@ fn visit_type_statement(env: Environment, node: Node) -> Result<(Environment, Ar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_use_statement(mut module: Module, node: Node) -> Result<Module, Error> {
|
||||||
|
assert_is_kind(&node, NodeKind::Use)?;
|
||||||
|
|
||||||
|
match node.value {
|
||||||
|
NodeValue::Use { name, props } => {
|
||||||
|
let name = typename_to_string(&name)?;
|
||||||
|
|
||||||
|
let ty = module.external_type(name, node.span)?;
|
||||||
|
|
||||||
|
for key in props.keys() {
|
||||||
|
if key == "as" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should really emit a warning...
|
||||||
|
eprintln!("Unexpected key {}", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(alias) = props.get("as") {
|
||||||
|
let name = typename_to_string(alias)?;
|
||||||
|
module.alias_type(name, ty, alias.span)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(module)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn typename_to_string(node: &Node) -> Result<String, Error> {
|
fn typename_to_string(node: &Node) -> Result<String, Error> {
|
||||||
assert_is_kind(&node, NodeKind::TypeName)?;
|
assert_is_kind(&node, NodeKind::TypeName)?;
|
||||||
|
|
||||||
|
@ -703,3 +776,14 @@ fn assert_is_kind(node: &Node, kind: NodeKind) -> Result<(), Error> {
|
||||||
received: node.kind.clone(),
|
received: node.kind.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn self_type(mut module: Module) -> Result<(Module, Arc<Type>), Error> {
|
||||||
|
let parent = module.types.peek().cloned()?;
|
||||||
|
|
||||||
|
if parent.is_protocol() {
|
||||||
|
let ty = module.unbound_type()?;
|
||||||
|
Ok((module, ty))
|
||||||
|
} else {
|
||||||
|
Ok((module, parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,10 +22,13 @@ pub use error::Error;
|
||||||
|
|
||||||
pub fn compile_file(input: &str) -> Result<(), Error> {
|
pub fn compile_file(input: &str) -> Result<(), Error> {
|
||||||
let untyped_ast = grammar::parse_file(input)?;
|
let untyped_ast = grammar::parse_file(input)?;
|
||||||
let env = ir::Environment::default();
|
// println!("AST: {:#?}", untyped_ast);
|
||||||
let env = ir::visit_nodes(env, untyped_ast)?;
|
|
||||||
|
|
||||||
println!("{:#?}", env);
|
let module = ir::Module::default();
|
||||||
|
let module = ir::visit_nodes(module, untyped_ast)?;
|
||||||
|
let module = ir::improve(module)?;
|
||||||
|
|
||||||
|
println!("IR {:#?}", module);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -37,6 +40,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_it_works() {
|
fn test_it_works() {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
|
use AbsoluteValue
|
||||||
|
use Option
|
||||||
|
use Outrun.NIF, as: NIF
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Integer
|
# Outrun.Core.Integer
|
||||||
|
|
||||||
|
@ -44,18 +51,18 @@ mod tests {
|
||||||
|
|
||||||
Has no constructor as it is created internally in the virtual machine by literals.
|
Has no constructor as it is created internally in the virtual machine by literals.
|
||||||
```
|
```
|
||||||
struct Outrun.Core.Integer(fruit: Wat), as: do
|
struct Outrun.Core.Integer, as: do
|
||||||
```doc
|
```doc
|
||||||
Computes the absolute value of `self`.
|
Computes the absolute value of `self`.
|
||||||
|
|
||||||
Returns none on overflow.
|
Returns none on overflow.
|
||||||
```
|
```
|
||||||
def abs(self: Self): Option, as: Outrun.NIF.integer_abs(self)
|
def abs(self: Self): Option, as: NIF.integer_abs(self)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
impl AbsoluteValue, for: Outrun.Core.Integer, as: do
|
impl AbsoluteValue, for: Outrun.Core.Integer, as: do
|
||||||
def abs(self: Self): Self, as: Outrun.NIF.integer_abs(self)
|
def abs(self: Self): Self, as: NIF.integer_abs(self)
|
||||||
end
|
end
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Addition
|
# Addition
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Bitwise And
|
# Bitwise And
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Bitwise Or
|
# Bitwise Or
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Bitwise Xor
|
# Bitwise Xor
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use Outrun.Core.Boolean
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Boolean
|
# Boolean
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Division
|
# Division
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Equality
|
# Equality
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use Outrun.NIF, as: NIF
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Error
|
# Error
|
||||||
```
|
```
|
||||||
|
@ -6,6 +8,6 @@ protocol Error, as: do
|
||||||
def message(self: Self): String
|
def message(self: Self): String
|
||||||
|
|
||||||
defs raise(error: Error): Any, as: do
|
defs raise(error: Error): Any, as: do
|
||||||
Outrun.NIF.error_raise(error)
|
NIF.error_raise(error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Exponentiation
|
# Exponentiation
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
use AbsoluteValue
|
||||||
|
use Addition
|
||||||
|
use Boolean
|
||||||
|
use Division
|
||||||
|
use Equality
|
||||||
|
use Greater
|
||||||
|
use GreaterOrEqual
|
||||||
|
use Less
|
||||||
|
use LessOrEqual
|
||||||
|
use Multiplication
|
||||||
|
use Negation
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Float
|
# Float
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Greater
|
# Greater
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Greater
|
||||||
|
use Equality
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# GreaterOrEqual
|
# GreaterOrEqual
|
||||||
|
|
||||||
|
@ -11,7 +16,7 @@ protocol GreaterOrEqual, requires: Greater + Equality, as: do
|
||||||
|
|
||||||
The default implementation delegates to the `Greater` and `Equality` protocols, however you should probably implement this function as a single comparison is more than likely much faster.
|
The default implementation delegates to the `Greater` and `Equality` protocols, however you should probably implement this function as a single comparison is more than likely much faster.
|
||||||
```
|
```
|
||||||
def greater_or_equal?(self: Greater, other: Any): Boolean, when: Greater.greater?(self, other), as: true
|
def greater_or_equal?(self: Self, other: Any): Boolean, when: Greater.greater?(self, other), as: true
|
||||||
def greater_or_equal?(self: Equality, other: Any): Boolean, when: Equality.equal?(self, other), as: true
|
def greater_or_equal?(self: Self, other: Any): Boolean, when: Equality.equal?(self, other), as: true
|
||||||
def greater_or_equal?(_self: Self, _other: Any), as: false
|
def greater_or_equal?(_self: Self, _other: Any): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,23 @@
|
||||||
|
use AbsoluteValue
|
||||||
|
use Addition
|
||||||
|
use BitwiseAnd
|
||||||
|
use BitwiseOr
|
||||||
|
use BitwiseXor
|
||||||
|
use Boolean
|
||||||
|
use Division
|
||||||
|
use Equality
|
||||||
|
use Exponentiation
|
||||||
|
use GreaterOrEqual
|
||||||
|
use Greater
|
||||||
|
use LessOrEqual
|
||||||
|
use Less
|
||||||
|
use Modulus
|
||||||
|
use Multiplication
|
||||||
|
use Negation
|
||||||
|
use ShiftLeft
|
||||||
|
use ShiftRight
|
||||||
|
use Subtraction
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Integer
|
# Integer
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Less
|
# Less
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Equality
|
||||||
|
use Less
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# LessOrEqual
|
# LessOrEqual
|
||||||
|
|
||||||
|
@ -11,7 +16,7 @@ protocol LessOrEqual, requires: Less + Equality, as: do
|
||||||
|
|
||||||
The default implementation delegates to the `Less` and `Equality` protocols, however you should probably implement this function as a single comparison is more than likely much faster.
|
The default implementation delegates to the `Less` and `Equality` protocols, however you should probably implement this function as a single comparison is more than likely much faster.
|
||||||
```
|
```
|
||||||
def less_or_equal?(self: Less, other: Any): Boolean, when: Less.less?(self, other), as: true
|
def less_or_equal?(self: Self, other: Any): Boolean, when: Less.less?(self, other), as: true
|
||||||
def less_or_equal?(self: Equality, other: Any): Boolean, when: Equality.equal?(self, other), as: true
|
def less_or_equal?(self: Self, other: Any): Boolean, when: Equality.equal?(self, other), as: true
|
||||||
def less_or_equal?(_self: Self, _other: Any): Boolean, as: false
|
def less_or_equal?(_self: Self, _other: Any): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# LogicalAnd
|
# LogicalAnd
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# LogicalOr
|
# LogicalOr
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Modulus
|
# Modulus
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Multiplication
|
# Multiplication
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Option
|
||||||
|
use Outrun.Core.Some, as: Some
|
||||||
|
use Outrun.Core.None, as: None
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Option
|
# Option
|
||||||
|
|
||||||
|
@ -29,10 +35,10 @@ protocol Option, as: do
|
||||||
```doc
|
```doc
|
||||||
Create a new "some" value using the default some type.
|
Create a new "some" value using the default some type.
|
||||||
```
|
```
|
||||||
defs some(value: Any): Option, as: Outrun.Core.Some.new(value)
|
defs some(value: Any): Option, as: Some.new(value)
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
Create a new "none" value using the default none type.
|
Create a new "none" value using the default none type.
|
||||||
```
|
```
|
||||||
defs none(): Option, as: Outrun.Core.None.new()
|
defs none(): Option, as: None.new()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Boolean
|
||||||
|
use Outrun.NIF, as: NIF
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Boolean
|
# Outrun.Core.Boolean
|
||||||
|
|
||||||
|
@ -15,7 +18,7 @@ end
|
||||||
impl Equality, for: Outrun.Core.Boolean, as: do
|
impl Equality, for: Outrun.Core.Boolean, as: do
|
||||||
def equal?(self: Self, other: Boolean): Boolean, as: do
|
def equal?(self: Self, other: Boolean): Boolean, as: do
|
||||||
let other = Boolean.true?(other)
|
let other = Boolean.true?(other)
|
||||||
Outrun.NIF.bool_eq(self, other)
|
NIF.bool_eq(self, other)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,12 +29,12 @@ impl LogicalAnd, for: Outrun.Core.Boolean, as: do
|
||||||
Concrete implementation of `&&`.
|
Concrete implementation of `&&`.
|
||||||
```
|
```
|
||||||
def and?(self: Self, other: Self): Option, as: do
|
def and?(self: Self, other: Self): Option, as: do
|
||||||
boolean_to_option(Outrun.NIF.bool_and(self, other))
|
boolean_to_option(NIF.bool_and(self, other))
|
||||||
end
|
end
|
||||||
|
|
||||||
def and?(self: Self, other: Boolean): Option, as: do
|
def and?(self: Self, other: Boolean): Option, as: do
|
||||||
let other = Boolean.true?(other)
|
let other = Boolean.true?(other)
|
||||||
let result = Outrun.NIF.bool_and(self, other)
|
let result = NIF.bool_and(self, other)
|
||||||
boolean_to_option(result)
|
boolean_to_option(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Error
|
||||||
|
use Result
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Error
|
# Outrun.Core.Error
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use Boolean
|
||||||
|
use Option
|
||||||
|
use Outrun.NIF
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Float
|
# Outrun.Core.Float
|
||||||
|
|
||||||
|
@ -6,60 +10,73 @@ The native implementation of `Float` based around Rust's `f64` type.
|
||||||
Has no constructor as it is created internally in the virtual machine by literals.
|
Has no constructor as it is created internally in the virtual machine by literals.
|
||||||
```
|
```
|
||||||
struct Outrun.Core.Float, as: do
|
struct Outrun.Core.Float, as: do
|
||||||
def nan?(self: Self): Boolean, as: Outrun.NIF.float_is_nan(self)
|
def nan?(self: Self): Boolean, as: NIF.float_is_nan(self)
|
||||||
def infinite?(self: Self): Boolean, as: Outrun.NIF.float_is_infinite(self)
|
def infinite?(self: Self): Boolean, as: NIF.float_is_infinite(self)
|
||||||
def finite?(self: Self): Boolean, as: Outrun.NIF.float_is_finite(self)
|
def finite?(self: Self): Boolean, as: NIF.float_is_finite(self)
|
||||||
def subnormal?(self: Self): Boolean, as: Outrun.NIF.float_is_subnormal(self)
|
def subnormal?(self: Self): Boolean, as: NIF.float_is_subnormal(self)
|
||||||
def normal?(self: Self): Boolean, as: Outrun.NIF.float_is_normal(self)
|
def normal?(self: Self): Boolean, as: NIF.float_is_normal(self)
|
||||||
def sign_positive?(self: Self): Boolean, as: Outrun.NIF.float_is_sign_positive(self)
|
def sign_positive?(self: Self): Boolean, as: NIF.float_is_sign_positive(self)
|
||||||
def sign_negative?(self: Self): Boolean, as: Outrun.NIF.float_is_sign_negative(self)
|
def sign_negative?(self: Self): Boolean, as: NIF.float_is_sign_negative(self)
|
||||||
def inverse(self: Self): Option, as: Outrun.NIF.float_inverse(self)
|
def inverse(self: Self): Option, as: NIF.float_inverse(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use AbsoluteValue
|
||||||
impl AbsoluteValue, for: Outrun.Core.Float, as: do
|
impl AbsoluteValue, for: Outrun.Core.Float, as: do
|
||||||
def abs(self: Self): Option, as: Outrun.NIF.float_abs(self)
|
def abs(self: Self): Option, as: NIF.float_abs(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Addition
|
||||||
impl Addition, for: Outrun.Core.Float, as: do
|
impl Addition, for: Outrun.Core.Float, as: do
|
||||||
def add(self: Self, other: Self): Option, as: Outrun.NIF.float_add(self, other)
|
def add(self: Self, other: Self): Option, as: NIF.float_add(self, other)
|
||||||
def add(_self: Self, _other: Any): Option, as: Option.none()
|
def add(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Division
|
||||||
impl Division, for: Outrun.Core.Float, as: do
|
impl Division, for: Outrun.Core.Float, as: do
|
||||||
def divide(self: Self, other: Self): Option, as: Outrun.NIF.float_div(self, other)
|
def divide(self: Self, other: Self): Option, as: NIF.float_div(self, other)
|
||||||
def divide(_self: Self, _other: Any): Option, as: Option.none()
|
def divide(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Equality
|
||||||
impl Equality, for: Outrun.Core.Float, as: do
|
impl Equality, for: Outrun.Core.Float, as: do
|
||||||
def equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.float_is_eq(self, other)
|
def equal?(self: Self, other: Self): Boolean, as: NIF.float_is_eq(self, other)
|
||||||
def equal?(_self: Self, _other: Self): Boolean, as: false
|
def equal?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Float
|
||||||
|
impl Float, for: Outrun.Core.Float
|
||||||
|
|
||||||
|
use Greater
|
||||||
impl Greater, for: Outrun.Core.Float, as: do
|
impl Greater, for: Outrun.Core.Float, as: do
|
||||||
def greater?(self: Self, other: Self): Boolean, as: Outrun.NIF.float_gt(self, other)
|
def greater?(self: Self, other: Self): Boolean, as: NIF.float_gt(self, other)
|
||||||
def greater?(_self: Self, _other: Self): Boolean, as: false
|
def greater?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use GreaterOrEqual
|
||||||
impl GreaterOrEqual, for: Outrun.Core.Float, as: do
|
impl GreaterOrEqual, for: Outrun.Core.Float, as: do
|
||||||
def greater_or_equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.float_gte(self, other)
|
def greater_or_equal?(self: Self, other: Self): Boolean, as: NIF.float_gte(self, other)
|
||||||
def greater_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
def greater_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Less
|
||||||
impl Less, for: Outrun.Core.Float, as: do
|
impl Less, for: Outrun.Core.Float, as: do
|
||||||
def less?(self: Self, other: Self): Boolean, as: Outrun.NIF.float_lt(self, other)
|
def less?(self: Self, other: Self): Boolean, as: NIF.float_lt(self, other)
|
||||||
def less?(_self: Self, _other: Self): Boolean, as: false
|
def less?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use LessOrEqual
|
||||||
impl LessOrEqual, for: Outrun.Core.Float, as: do
|
impl LessOrEqual, for: Outrun.Core.Float, as: do
|
||||||
def less_or_equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.float_lte(self, other)
|
def less_or_equal?(self: Self, other: Self): Boolean, as: NIF.float_lte(self, other)
|
||||||
def less_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
def less_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Multiplication
|
||||||
impl Multiplication, for: Outrun.Core.Float, as: do
|
impl Multiplication, for: Outrun.Core.Float, as: do
|
||||||
def multiply(self: Self, other: Self): Option, as: Outrun.NIF.float_mul(self, other)
|
def multiply(self: Self, other: Self): Option, as: NIF.float_mul(self, other)
|
||||||
def multiply(_self: Self, _other: Any): Option, as: Option.none()
|
def multiply(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Negation
|
||||||
impl Negation, for: Outrun.Core.Float, as: do
|
impl Negation, for: Outrun.Core.Float, as: do
|
||||||
def neg(self: Self): Option, as: Outrun.NIF.float_neg(self)
|
def neg(self: Self): Option, as: NIF.float_neg(self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Option
|
||||||
|
use Outrun.NIF, as: NIF
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Integer
|
# Outrun.Core.Integer
|
||||||
|
|
||||||
|
@ -11,100 +14,117 @@ struct Outrun.Core.Integer, as: do
|
||||||
|
|
||||||
Returns none on overflow.
|
Returns none on overflow.
|
||||||
```
|
```
|
||||||
def abs(self: Self): Option, as: Outrun.NIF.integer_abs(self)
|
def abs(self: Self): Option, as: NIF.integer_abs(self)
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
Returns whether the value of `self` is greater than zero.
|
Returns whether the value of `self` is greater than zero.
|
||||||
```
|
```
|
||||||
def positive?(self: Self): Self, as: Outrun.NIF.integer_gt(self, 0)
|
def positive?(self: Self): Self, as: NIF.integer_gt(self, 0)
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
Returns whether the value of `self` equals zero.
|
Returns whether the value of `self` equals zero.
|
||||||
```
|
```
|
||||||
def zero?(self: Self): Self, as: Outrun.NIF.integer_eq(self, 0)
|
def zero?(self: Self): Self, as: NIF.integer_eq(self, 0)
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
Returns whether the value of `self` is less than zero.
|
Returns whether the value of `self` is less than zero.
|
||||||
```
|
```
|
||||||
def negative?(self: Self): Self, as: Outrun.NIF.integer_lt(self, 0)
|
def negative?(self: Self): Self, as: NIF.integer_lt(self, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use AbsoluteValue
|
||||||
impl AbsoluteValue, for: Outrun.Core.Integer, as: do
|
impl AbsoluteValue, for: Outrun.Core.Integer, as: do
|
||||||
def abs(self: Self): Self, as: Outrun.NIF.integer_abs(self)
|
def abs(self: Self): Self, as: NIF.integer_abs(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Addition
|
||||||
impl Addition, for: Outrun.Core.Integer, as: do
|
impl Addition, for: Outrun.Core.Integer, as: do
|
||||||
def add(self: Self, other: Self): Option, as: Outrun.NIF.integer_add(self, other)
|
def add(self: Self, other: Self): Option, as: NIF.integer_add(self, other)
|
||||||
def add(_self: Self, _other: Any): Option, as: Option.none()
|
def add(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use BitwiseAnd
|
||||||
impl BitwiseAnd, for: Outrun.Core.Integer, as: do
|
impl BitwiseAnd, for: Outrun.Core.Integer, as: do
|
||||||
def and(self: Self, other: Self): Option, as: Outrun.NIF.integer_band(self, other)
|
def and(self: Self, other: Self): Option, as: NIF.integer_band(self, other)
|
||||||
def and(_self: Self, _other: Any): Option, as: Option.none()
|
def and(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use BitwiseOr
|
||||||
impl BitwiseOr, for: Outrun.Core.Integer, as: do
|
impl BitwiseOr, for: Outrun.Core.Integer, as: do
|
||||||
def or(self: Self, other: Self): Option, as: Outrun.NIF.integer_bor(self, other)
|
def or(self: Self, other: Self): Option, as: NIF.integer_bor(self, other)
|
||||||
def or(_self: Self, _other: Any): Option, as: Option.none()
|
def or(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use BitwiseXor
|
||||||
impl BitwiseXor, for: Outrun.Core.Integer, as: do
|
impl BitwiseXor, for: Outrun.Core.Integer, as: do
|
||||||
def xor(self: Self, other: Self): Option, as: Outrun.NIF.integer_bxor(self, other)
|
def xor(self: Self, other: Self): Option, as: NIF.integer_bxor(self, other)
|
||||||
def xor(_self: Self, _other: Any): Option, as: Option.none()
|
def xor(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Division
|
||||||
impl Division, for: Outrun.Core.Integer, as: do
|
impl Division, for: Outrun.Core.Integer, as: do
|
||||||
def divide(self: Self, other: Self): Option, as: Outrun.NIF.integer_div(self, other)
|
def divide(self: Self, other: Self): Option, as: NIF.integer_div(self, other)
|
||||||
def divide(_self: Self, _other: Any): Option, as: Option.none()
|
def divide(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Equality
|
||||||
impl Equality, for: Outrun.Core.Integer, as: do
|
impl Equality, for: Outrun.Core.Integer, as: do
|
||||||
def equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.integer_eq(self, other)
|
def equal?(self: Self, other: Self): Boolean, as: NIF.integer_eq(self, other)
|
||||||
def equal?(_self: Self, _other: Any): Boolean, as: false
|
def equal?(_self: Self, _other: Any): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Exponentiation
|
||||||
impl Exponentiation, for: Outrun.Core.Integer, as: do
|
impl Exponentiation, for: Outrun.Core.Integer, as: do
|
||||||
def raise(self: Self, other: Self): Option, as: Outrun.NIF.integer_expo(self, other)
|
def raise(self: Self, other: Self): Option, as: NIF.integer_expo(self, other)
|
||||||
def raise(_self: Self, _other: Any): Option, as: Option.none()
|
def raise(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use GreaterOrEqual
|
||||||
impl GreaterOrEqual, for: Outrun.Core.Integer, as: do
|
impl GreaterOrEqual, for: Outrun.Core.Integer, as: do
|
||||||
def greater_or_equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.integer_gte(self, other)
|
def greater_or_equal?(self: Self, other: Self): Boolean, as: NIF.integer_gte(self, other)
|
||||||
def greater_or_equal?(_self: Self, _other: Any): Boolean, as: false
|
def greater_or_equal?(_self: Self, _other: Any): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Greater
|
||||||
impl Greater, for: Outrun.Core.Integer, as: do
|
impl Greater, for: Outrun.Core.Integer, as: do
|
||||||
def greater?(self: Self, other: Self): Boolean, as: Outrun.NIF.integer_gt(self, other)
|
def greater?(self: Self, other: Self): Boolean, as: NIF.integer_gt(self, other)
|
||||||
def greater?(_self: Self, _other: Any): Boolean, as: false
|
def greater?(_self: Self, _other: Any): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Integer
|
||||||
impl Integer, for: Outrun.Core.Integer
|
impl Integer, for: Outrun.Core.Integer
|
||||||
|
|
||||||
|
use LessOrEqual
|
||||||
impl LessOrEqual, for: Outrun.Core.Integer, as: do
|
impl LessOrEqual, for: Outrun.Core.Integer, as: do
|
||||||
def less_or_equal?(self: Self, other: Self): Boolean, as: Outrun.NIF.integer_lte(self, other)
|
def less_or_equal?(self: Self, other: Self): Boolean, as: NIF.integer_lte(self, other)
|
||||||
def less_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
def less_or_equal?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Less
|
||||||
impl Less, for: Outrun.Core.Integer, as: do
|
impl Less, for: Outrun.Core.Integer, as: do
|
||||||
def less?(self: Self, other: Self): Boolean, as: Outrun.NIF.integer_lt(self, other)
|
def less?(self: Self, other: Self): Boolean, as: NIF.integer_lt(self, other)
|
||||||
def less?(_self: Self, _other: Self): Boolean, as: false
|
def less?(_self: Self, _other: Self): Boolean, as: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Modulus
|
||||||
impl Modulus, for: Outrun.Core.Integer, as: do
|
impl Modulus, for: Outrun.Core.Integer, as: do
|
||||||
def modulo(self: Self, other: Self): Option, as: Outrun.NIF.integer_mod(self, other)
|
def modulo(self: Self, other: Self): Option, as: NIF.integer_mod(self, other)
|
||||||
def modulo(_self: Self, _other: Any): Option, as: Option.none()
|
def modulo(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Multiplication
|
||||||
impl Multiplication, for: Outrun.Core.Integer, as: do
|
impl Multiplication, for: Outrun.Core.Integer, as: do
|
||||||
def multiply(self: Self, other: Self): Option, as: Outrun.NIF.integer_mul(self, other)
|
def multiply(self: Self, other: Self): Option, as: NIF.integer_mul(self, other)
|
||||||
def multiply(_self: Self, _other: Any): Option, as: Option.none()
|
def multiply(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Negation
|
||||||
impl Negation, for: Outrun.Core.Integer, as: do
|
impl Negation, for: Outrun.Core.Integer, as: do
|
||||||
def neg(self: Self): Option, as: Outrun.NIF.integer_neg(self)
|
def neg(self: Self): Option, as: NIF.integer_neg(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
use Subtraction
|
||||||
impl Subtraction, for: Outrun.Core.Integer, as: do
|
impl Subtraction, for: Outrun.Core.Integer, as: do
|
||||||
def subtract(self: Self, other: Self): Option, as: Outrun.NIF.integer_sub(self, other)
|
def subtract(self: Self, other: Self): Option, as: NIF.integer_sub(self, other)
|
||||||
def subtract(_self: Self, _other: Any): Option, as: Option.none()
|
def subtract(_self: Self, _other: Any): Option, as: Option.none()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Boolean
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Some
|
# Outrun.Core.Some
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ end
|
||||||
|
|
||||||
struct Outrun.Core.None.UnwrapError
|
struct Outrun.Core.None.UnwrapError
|
||||||
|
|
||||||
|
use Error
|
||||||
impl Error, for: Outrun.Core.None.UnwrapError, as: do
|
impl Error, for: Outrun.Core.None.UnwrapError, as: do
|
||||||
def message(self: Self): String, as: "Attempt to unwrap a None value"
|
def message(self: Self): String, as: "Attempt to unwrap a None value"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use Any
|
||||||
|
use Result
|
||||||
|
use String
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Okay
|
# Outrun.Core.Okay
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Outrun.Core.Some
|
# Outrun.Core.Some
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
use Any
|
||||||
|
use Boolean
|
||||||
|
use Error
|
||||||
|
use Result
|
||||||
|
use Outrun.Core.Okay
|
||||||
|
use Outrun.Core.Error
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Result
|
# Result
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Shift Left
|
# Shift Left
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Shift Right
|
# Shift Right
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use Any
|
||||||
|
use Option
|
||||||
|
|
||||||
```doc
|
```doc
|
||||||
# Subtraction
|
# Subtraction
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue