Begin revising built-in functions
This commit is contained in:
parent
fe1e27fd70
commit
fb78798a1d
35
dust-lang/src/abstract_tree/built_in_function_call.rs
Normal file
35
dust-lang/src/abstract_tree/built_in_function_call.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
io::stdin,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{Action, Type},
|
||||
context::Context,
|
||||
error::RuntimeError,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Expression, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum BuiltInFunctionCall {
|
||||
ReadLine,
|
||||
Sleep(Expression),
|
||||
WriteLine(Expression),
|
||||
}
|
||||
|
||||
impl AbstractNode for BuiltInFunctionCall {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -5,12 +5,13 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractNode, Action, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, Type,
|
||||
ValueNode, WithPosition,
|
||||
AbstractNode, Action, BuiltInFunctionCall, FunctionCall, ListIndex, Logic, MapIndex, Math,
|
||||
SourcePosition, Type, ValueNode, WithPosition,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Expression {
|
||||
BuiltInFunctionCall(WithPosition<Box<BuiltInFunctionCall>>),
|
||||
FunctionCall(WithPosition<FunctionCall>),
|
||||
Identifier(WithPosition<Identifier>),
|
||||
MapIndex(WithPosition<Box<MapIndex>>),
|
||||
@ -30,6 +31,7 @@ impl Expression {
|
||||
Expression::Logic(inner) => inner.position,
|
||||
Expression::Math(inner) => inner.position,
|
||||
Expression::Value(inner) => inner.position,
|
||||
Expression::BuiltInFunctionCall(inner) => inner.position,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,6 +55,7 @@ impl AbstractNode for Expression {
|
||||
Expression::Logic(logic) => logic.node.expected_type(_context),
|
||||
Expression::Math(math) => math.node.expected_type(_context),
|
||||
Expression::Value(value_node) => value_node.node.expected_type(_context),
|
||||
Expression::BuiltInFunctionCall(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +77,7 @@ impl AbstractNode for Expression {
|
||||
Expression::Logic(logic) => logic.node.validate(context),
|
||||
Expression::Math(math) => math.node.validate(context),
|
||||
Expression::Value(value_node) => value_node.node.validate(context),
|
||||
Expression::BuiltInFunctionCall(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,6 +101,7 @@ impl AbstractNode for Expression {
|
||||
Expression::Logic(logic) => logic.node.run(_context),
|
||||
Expression::Math(math) => math.node.run(_context),
|
||||
Expression::Value(value_node) => value_node.node.run(_context),
|
||||
Expression::BuiltInFunctionCall(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
value::{Function, ParsedFunction, ValueInner},
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Expression, Type, WithPosition};
|
||||
@ -133,11 +133,8 @@ impl AbstractNode for FunctionCall {
|
||||
|
||||
let function_context = Context::new();
|
||||
|
||||
if let Function::Parsed(ParsedFunction {
|
||||
type_parameters, ..
|
||||
}) = function
|
||||
{
|
||||
for (type_parameter, type_argument) in type_parameters
|
||||
for (type_parameter, type_argument) in function
|
||||
.type_parameters()
|
||||
.iter()
|
||||
.map(|r#type| r#type.node.clone())
|
||||
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
|
||||
@ -146,7 +143,6 @@ impl AbstractNode for FunctionCall {
|
||||
function_context.set_type(identifier, type_argument)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function_context.inherit_data_from(&context)?;
|
||||
function.clone().call(arguments, function_context)
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod assignment;
|
||||
pub mod async_block;
|
||||
pub mod block;
|
||||
pub mod built_in_function_call;
|
||||
pub mod expression;
|
||||
pub mod function_call;
|
||||
pub mod if_else;
|
||||
@ -23,6 +24,7 @@ pub use self::{
|
||||
assignment::{Assignment, AssignmentOperator},
|
||||
async_block::AsyncBlock,
|
||||
block::Block,
|
||||
built_in_function_call::BuiltInFunctionCall,
|
||||
expression::Expression,
|
||||
function_call::FunctionCall,
|
||||
if_else::IfElse,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
||||
|
||||
use crate::{
|
||||
built_in_functions::BuiltInFunction,
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
@ -13,7 +12,6 @@ use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueNode {
|
||||
Boolean(bool),
|
||||
BuiltInFunction(BuiltInFunction),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
List(Vec<Expression>),
|
||||
@ -88,7 +86,6 @@ impl AbstractNode for ValueNode {
|
||||
fields: types,
|
||||
}
|
||||
}
|
||||
ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(),
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
@ -260,9 +257,6 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
Value::structure(name, fields)
|
||||
}
|
||||
ValueNode::BuiltInFunction(built_in_function) => {
|
||||
Value::built_in_function(built_in_function)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Action::Return(value))
|
||||
@ -358,8 +352,6 @@ impl Ord for ValueNode {
|
||||
}
|
||||
}
|
||||
(Structure { .. }, _) => Ordering::Greater,
|
||||
(BuiltInFunction(_), BuiltInFunction(_)) => todo!(),
|
||||
(BuiltInFunction(_), _) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
io::stdin,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{Action, Type, WithPos},
|
||||
context::Context,
|
||||
error::RuntimeError,
|
||||
value::ValueInner,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum BuiltInFunction {
|
||||
ReadLine,
|
||||
Sleep,
|
||||
WriteLine,
|
||||
}
|
||||
|
||||
impl BuiltInFunction {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
BuiltInFunction::ReadLine => "__READ_LINE__",
|
||||
BuiltInFunction::Sleep => "__SLEEP__",
|
||||
BuiltInFunction::WriteLine => "__WRITE_LINE__",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value(self) -> Value {
|
||||
Value::built_in_function(self)
|
||||
}
|
||||
|
||||
pub fn r#type(&self) -> Type {
|
||||
match self {
|
||||
BuiltInFunction::WriteLine => Type::Function {
|
||||
parameter_types: vec![Type::String.with_position((0, 0))],
|
||||
return_type: Box::new(Type::None.with_position((0, 0))),
|
||||
},
|
||||
_ => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, arguments: Vec<Value>, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
match self {
|
||||
// "INT_RANDOM_RANGE" => {
|
||||
// let range = arguments.get(0).unwrap();
|
||||
|
||||
// if let ValueInner::Range(range) = range.inner().as_ref() {
|
||||
// let random = thread_rng().gen_range(range.clone());
|
||||
|
||||
// Ok(Action::Return(Value::integer(random)))
|
||||
// } else {
|
||||
// panic!("Built-in function cannot have a non-function type.")
|
||||
// }
|
||||
// }
|
||||
BuiltInFunction::ReadLine => {
|
||||
let mut input = String::new();
|
||||
|
||||
stdin().read_line(&mut input)?;
|
||||
|
||||
Ok(Action::Return(Value::string(input)))
|
||||
}
|
||||
BuiltInFunction::Sleep => {
|
||||
if let ValueInner::Integer(milliseconds) = arguments[0].inner().as_ref() {
|
||||
thread::sleep(Duration::from_millis(*milliseconds as u64));
|
||||
}
|
||||
|
||||
Ok(Action::None)
|
||||
}
|
||||
BuiltInFunction::WriteLine => {
|
||||
println!("{}", arguments[0]);
|
||||
|
||||
Ok(Action::None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuiltInFunction {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name())
|
||||
}
|
||||
}
|
@ -5,12 +5,11 @@ use std::{
|
||||
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{built_in_functions::BuiltInFunction, error::Error};
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Token<'src> {
|
||||
Boolean(bool),
|
||||
BuiltInFunction(BuiltInFunction),
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
String(&'src str),
|
||||
@ -24,7 +23,6 @@ impl<'src> Display for Token<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Token::Boolean(boolean) => write!(f, "{boolean}"),
|
||||
Token::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"),
|
||||
Token::Integer(integer) => write!(f, "{integer}"),
|
||||
Token::Float(float) => write!(f, "{float}"),
|
||||
Token::String(string) => write!(f, "{string}"),
|
||||
@ -51,11 +49,14 @@ pub enum Keyword {
|
||||
Map,
|
||||
None,
|
||||
Range,
|
||||
ReadLine,
|
||||
Sleep,
|
||||
Struct,
|
||||
Str,
|
||||
Type,
|
||||
Loop,
|
||||
While,
|
||||
WriteLine,
|
||||
}
|
||||
|
||||
impl Display for Keyword {
|
||||
@ -79,6 +80,9 @@ impl Display for Keyword {
|
||||
Keyword::Loop => write!(f, "loop"),
|
||||
Keyword::While => write!(f, "while"),
|
||||
Keyword::Type => write!(f, "type"),
|
||||
Keyword::ReadLine => write!(f, "READ_LINE"),
|
||||
Keyword::Sleep => write!(f, "SLEEP"),
|
||||
Keyword::WriteLine => write!(f, "WRITE_LINE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,6 +150,7 @@ pub enum Control {
|
||||
Semicolon,
|
||||
SkinnyArrow,
|
||||
FatArrow,
|
||||
DoubleUnderscore,
|
||||
}
|
||||
|
||||
impl Display for Control {
|
||||
@ -167,6 +172,7 @@ impl Display for Control {
|
||||
Control::DoubleDot => write!(f, ".."),
|
||||
Control::SkinnyArrow => write!(f, "->"),
|
||||
Control::FatArrow => write!(f, "=>"),
|
||||
Control::DoubleUnderscore => write!(f, "__"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,6 +278,7 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
just("..").to(Control::DoubleDot),
|
||||
just(".").to(Control::Dot),
|
||||
just("$").to(Control::Dollar),
|
||||
just("__").to(Control::DoubleUnderscore),
|
||||
))
|
||||
.map(Token::Control);
|
||||
|
||||
@ -294,26 +301,14 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
just("type").to(Keyword::Type),
|
||||
just("loop").to(Keyword::Loop),
|
||||
just("while").to(Keyword::While),
|
||||
just("READ_LINE").to(Keyword::ReadLine),
|
||||
just("SLEEP").to(Keyword::Sleep),
|
||||
just("WRITE_LINE").to(Keyword::WriteLine),
|
||||
))
|
||||
.map(Token::Keyword);
|
||||
|
||||
let built_in_function = choice((
|
||||
just(BuiltInFunction::ReadLine.name()).to(BuiltInFunction::ReadLine),
|
||||
just(BuiltInFunction::Sleep.name()).to(BuiltInFunction::Sleep),
|
||||
just(BuiltInFunction::WriteLine.name()).to(BuiltInFunction::WriteLine),
|
||||
))
|
||||
.map(Token::BuiltInFunction);
|
||||
|
||||
choice((
|
||||
boolean,
|
||||
float,
|
||||
integer,
|
||||
string,
|
||||
keyword,
|
||||
identifier,
|
||||
control,
|
||||
operator,
|
||||
built_in_function,
|
||||
boolean, float, integer, string, keyword, identifier, control, operator,
|
||||
))
|
||||
.map_with(|token, state| (token, state.span()))
|
||||
.padded()
|
||||
|
@ -1,5 +1,4 @@
|
||||
pub mod abstract_tree;
|
||||
pub mod built_in_functions;
|
||||
pub mod context;
|
||||
pub mod error;
|
||||
pub mod identifier;
|
||||
|
@ -255,14 +255,20 @@ pub fn parser<'src>(
|
||||
},
|
||||
);
|
||||
|
||||
let built_in_function = {
|
||||
select! {
|
||||
Token::BuiltInFunction(built_in_function) => built_in_function,
|
||||
}
|
||||
}
|
||||
.map_with(|built_in_function, state| {
|
||||
Expression::Value(
|
||||
ValueNode::BuiltInFunction(built_in_function).with_position(state.span()),
|
||||
let built_in_function_call = just(Token::Control(Control::DoubleUnderscore))
|
||||
.ignore_then(choice((
|
||||
just(Token::Keyword(Keyword::ReadLine)).to(BuiltInFunctionCall::ReadLine),
|
||||
just(Token::Keyword(Keyword::Sleep))
|
||||
.ignore_then(expression.clone())
|
||||
.map(|expression| BuiltInFunctionCall::Sleep(expression)),
|
||||
just(Token::Keyword(Keyword::WriteLine))
|
||||
.ignore_then(expression.clone())
|
||||
.map(|expression| BuiltInFunctionCall::WriteLine(expression)),
|
||||
)))
|
||||
.then_ignore(just(Token::Control(Control::DoubleUnderscore)))
|
||||
.map_with(|built_in_function_call, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(built_in_function_call).with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
@ -307,7 +313,6 @@ pub fn parser<'src>(
|
||||
range.clone(),
|
||||
structure_instance.clone(),
|
||||
parsed_function.clone(),
|
||||
built_in_function.clone(),
|
||||
list.clone(),
|
||||
map.clone(),
|
||||
basic_value.clone(),
|
||||
@ -475,11 +480,11 @@ pub fn parser<'src>(
|
||||
));
|
||||
|
||||
choice((
|
||||
built_in_function_call,
|
||||
logic_math_indexes_and_function_calls,
|
||||
range,
|
||||
structure_instance,
|
||||
parsed_function,
|
||||
built_in_function,
|
||||
list,
|
||||
map,
|
||||
basic_value,
|
||||
@ -588,7 +593,7 @@ pub fn parser<'src>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{built_in_functions::BuiltInFunction, lexer::lex};
|
||||
use crate::lexer::lex;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -596,10 +601,20 @@ mod tests {
|
||||
fn built_in_function() {
|
||||
assert_eq!(
|
||||
parse(&lex("__READ_LINE__").unwrap()).unwrap()[0],
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::BuiltInFunction(BuiltInFunction::ReadLine).with_position((0, 13))
|
||||
Statement::Expression(Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::ReadLine).with_position((0, 13))
|
||||
))
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parse(&lex("__WRITE_LINE 'hiya'__").unwrap()).unwrap()[0],
|
||||
Statement::Expression(Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::WriteLine(Expression::Value(
|
||||
ValueNode::String("hiya".to_string()).with_position((13, 19))
|
||||
)))
|
||||
.with_position((0, 21))
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -14,7 +14,6 @@ use stanza::{
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition},
|
||||
built_in_functions::BuiltInFunction,
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
@ -62,24 +61,18 @@ impl Value {
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||
ParsedFunction {
|
||||
Value(Arc::new(ValueInner::Function(Function {
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
},
|
||||
))))
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn structure(name: WithPosition<Identifier>, fields: Vec<(Identifier, Value)>) -> Self {
|
||||
Value(Arc::new(ValueInner::Structure { name, fields }))
|
||||
}
|
||||
|
||||
pub fn built_in_function(function: BuiltInFunction) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function::BuiltIn(function))))
|
||||
}
|
||||
|
||||
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||
self.0.r#type(context)
|
||||
}
|
||||
@ -139,12 +132,12 @@ impl Display for Value {
|
||||
}
|
||||
ValueInner::Range(_) => todo!(),
|
||||
ValueInner::String(string) => write!(f, "{string}"),
|
||||
ValueInner::Function(Function::Parsed(ParsedFunction {
|
||||
ValueInner::Function(Function {
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
})) => {
|
||||
}) => {
|
||||
if !type_arguments.is_empty() {
|
||||
write!(f, "(")?;
|
||||
|
||||
@ -167,8 +160,8 @@ impl Display for Value {
|
||||
|
||||
write!(f, "): {} {:?}", return_type.node, body.node)
|
||||
}
|
||||
ValueInner::Function(Function::BuiltIn(built_in_function)) => {
|
||||
write!(f, "{built_in_function}")
|
||||
ValueInner::Function(function) => {
|
||||
write!(f, "{function}")
|
||||
}
|
||||
ValueInner::Structure { name, fields } => {
|
||||
let mut table = create_table();
|
||||
@ -231,18 +224,13 @@ impl ValueInner {
|
||||
ValueInner::Map(_) => Type::Map,
|
||||
ValueInner::Range(_) => Type::Range,
|
||||
ValueInner::String(_) => Type::String,
|
||||
ValueInner::Function(function) => match function {
|
||||
Function::Parsed(parsed_function) => Type::Function {
|
||||
parameter_types: parsed_function
|
||||
ValueInner::Function(function) => Type::Function {
|
||||
parameter_types: function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, r#type)| r#type.clone())
|
||||
.collect(),
|
||||
return_type: Box::new(parsed_function.return_type.clone()),
|
||||
},
|
||||
Function::BuiltIn(built_in_function) => {
|
||||
built_in_function.clone().as_value().r#type(context)?
|
||||
}
|
||||
return_type: Box::new(function.return_type.clone()),
|
||||
},
|
||||
ValueInner::Structure { name, .. } => {
|
||||
if let Some(r#type) = context.get_type(&name.node)? {
|
||||
@ -321,34 +309,29 @@ impl Ord for ValueInner {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Function {
|
||||
Parsed(ParsedFunction),
|
||||
BuiltIn(BuiltInFunction),
|
||||
pub struct Function {
|
||||
type_parameters: Vec<WithPosition<Type>>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn type_parameters(&self) -> &Vec<WithPosition<Type>> {
|
||||
&self.type_parameters
|
||||
}
|
||||
|
||||
pub fn call(self, arguments: Vec<Value>, context: Context) -> Result<Action, RuntimeError> {
|
||||
let action = match self {
|
||||
Function::Parsed(ParsedFunction {
|
||||
parameters, body, ..
|
||||
}) => {
|
||||
for ((identifier, _), value) in parameters.into_iter().zip(arguments.into_iter()) {
|
||||
for ((identifier, _), value) in self.parameters.into_iter().zip(arguments.into_iter()) {
|
||||
context.set_value(identifier.clone(), value)?;
|
||||
}
|
||||
|
||||
body.node.run(&context)?
|
||||
}
|
||||
Function::BuiltIn(built_in_function) => built_in_function.call(arguments, &context)?,
|
||||
};
|
||||
|
||||
Ok(action)
|
||||
self.body.node.run(&context)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ParsedFunction {
|
||||
pub type_parameters: Vec<WithPosition<Type>>,
|
||||
pub parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
pub return_type: WithPosition<Type>,
|
||||
pub body: WithPosition<Block>,
|
||||
impl Display for Function {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user