wip: working on type resolution.

This commit is contained in:
James Harton 2022-08-19 16:25:42 +12:00
parent 4e476626ed
commit 40717b6c78
47 changed files with 883 additions and 350 deletions

View file

@ -14,6 +14,7 @@
"defstruct", "defstruct",
"defstructfield", "defstructfield",
"defstructproperty", "defstructproperty",
"defuseproperty",
"hashrocket", "hashrocket",
"indoc", "indoc",
"lexer", "lexer",

View file

@ -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};

View file

@ -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))
} }
} }

View file

@ -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>,
},
} }

View file

@ -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 }

View file

@ -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)?;

View file

@ -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,
}
}
}

View file

@ -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)
}
} }

View 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,
}
}
}

View file

@ -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)
}

View 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
}

View 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),
}

View 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)
}

View file

@ -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(),
} }
} }

View file

@ -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))
}
}

View file

@ -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
"#; "#;

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Addition # Addition

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Bitwise And # Bitwise And

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Bitwise Or # Bitwise Or

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Bitwise Xor # Bitwise Xor

View file

@ -1,3 +1,5 @@
use Outrun.Core.Boolean
```doc ```doc
# Boolean # Boolean

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Division # Division

View file

@ -1,3 +1,6 @@
use Any
use Boolean
```doc ```doc
# Equality # Equality

View file

@ -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

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Exponentiation # Exponentiation

View file

@ -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

View file

@ -1,3 +1,6 @@
use Any
use Boolean
```doc ```doc
# Greater # Greater

View file

@ -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

View file

@ -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

View file

@ -1,3 +1,6 @@
use Any
use Boolean
```doc ```doc
# Less # Less

View file

@ -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

View file

@ -1,3 +1,7 @@
use Any
use Boolean
use Option
```doc ```doc
# LogicalAnd # LogicalAnd

View file

@ -1,3 +1,6 @@
use Any
use Boolean
```doc ```doc
# LogicalOr # LogicalOr

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Modulus # Modulus

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Multiplication # Multiplication

View file

@ -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

View file

@ -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

View file

@ -1,3 +1,6 @@
use Error
use Result
```doc ```doc
# Outrun.Core.Error # Outrun.Core.Error

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,3 +1,7 @@
use Any
use Result
use String
```doc ```doc
# Outrun.Core.Okay # Outrun.Core.Okay

View file

@ -1,3 +1,7 @@
use Any
use Boolean
use Option
```doc ```doc
# Outrun.Core.Some # Outrun.Core.Some

View file

@ -1,3 +1,10 @@
use Any
use Boolean
use Error
use Result
use Outrun.Core.Okay
use Outrun.Core.Error
```doc ```doc
# Result # Result

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Shift Left # Shift Left

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Shift Right # Shift Right

View file

@ -1,3 +1,6 @@
use Any
use Option
```doc ```doc
# Subtraction # Subtraction