Compare commits

...

7 Commits

14 changed files with 389 additions and 151 deletions

View File

@ -9,7 +9,7 @@ fn main() -> u16 {
let mut list = array(); let mut list = array();
list[1] = 5; // list[1] = 5;
return list[0]; return list[0];
} }

View File

@ -19,7 +19,7 @@ fn main() {
ExprKind::BinOp( ExprKind::BinOp(
BinaryOperator::Cmp(CmpOperator::GT), BinaryOperator::Cmp(CmpOperator::GT),
Box::new(Expression( Box::new(Expression(
ExprKind::Variable(VariableReference( ExprKind::Variable(NamedVariableRef(
TypeKind::I32, TypeKind::I32,
"N".to_string(), "N".to_string(),
Default::default(), Default::default(),
@ -52,7 +52,7 @@ fn main() {
BinaryOperator::Minus, BinaryOperator::Minus,
Box::new(Expression( Box::new(Expression(
ExprKind::Variable( ExprKind::Variable(
VariableReference( NamedVariableRef(
TypeKind::I32, TypeKind::I32,
fibonacci_n.clone(), fibonacci_n.clone(),
Default::default(), Default::default(),
@ -80,7 +80,7 @@ fn main() {
BinaryOperator::Minus, BinaryOperator::Minus,
Box::new(Expression( Box::new(Expression(
ExprKind::Variable( ExprKind::Variable(
VariableReference( NamedVariableRef(
TypeKind::I32, TypeKind::I32,
fibonacci_n.clone(), fibonacci_n.clone(),
Default::default(), Default::default(),

View File

@ -133,8 +133,11 @@ pub struct Block(
); );
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum VariableReference { pub struct VariableReference(pub VariableReferenceKind, pub TokenRange);
Name(String),
#[derive(Debug, Clone)]
pub enum VariableReferenceKind {
Name(String, TokenRange),
Index(Box<VariableReference>, u64), Index(Box<VariableReference>, u64),
} }

View File

@ -350,7 +350,7 @@ impl Parse for Block {
stream.expect(Token::BraceOpen)?; stream.expect(Token::BraceOpen)?;
while !matches!(stream.peek(), Some(Token::BraceClose)) { while !matches!(stream.peek(), Some(Token::BraceClose)) {
if let Some((r_type, e)) = return_stmt.take() { if let Some((_, e)) = return_stmt.take() {
// Special list of expressions that are simply not warned about, // Special list of expressions that are simply not warned about,
// if semicolon is missing. // if semicolon is missing.
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) { if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
@ -383,12 +383,18 @@ impl Parse for Block {
impl Parse for VariableReference { impl Parse for VariableReference {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
if let Some(Token::Identifier(ident)) = stream.next() { if let Some(Token::Identifier(ident)) = stream.next() {
let mut var_ref = VariableReference::Name(ident); let mut var_ref = VariableReference(
VariableReferenceKind::Name(ident, stream.get_one_token_range()),
stream.get_range().unwrap(),
);
dbg!(&var_ref); dbg!(&var_ref);
while let Ok(ValueIndex(idx)) = stream.parse() { while let Ok(ValueIndex(idx)) = stream.parse() {
dbg!(idx); dbg!(idx);
var_ref = VariableReference::Index(Box::new(var_ref), idx); var_ref = VariableReference(
VariableReferenceKind::Index(Box::new(var_ref), idx),
stream.get_range().unwrap(),
);
} }
Ok(var_ref) Ok(var_ref)

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::{self}, ast::{self},
mir::{self, StmtKind, VariableReference}, mir::{self, NamedVariableRef, StmtKind},
}; };
impl mir::Context { impl mir::Context {
@ -61,7 +61,7 @@ impl ast::Block {
let (kind, range) = match statement { let (kind, range) = match statement {
ast::BlockLevelStatement::Let(s_let) => ( ast::BlockLevelStatement::Let(s_let) => (
mir::StmtKind::Let( mir::StmtKind::Let(
mir::VariableReference( mir::NamedVariableRef(
s_let s_let
.1 .1
.clone() .clone()
@ -75,15 +75,8 @@ impl ast::Block {
), ),
s_let.4, s_let.4,
), ),
ast::BlockLevelStatement::Set(name, expression, range) => ( ast::BlockLevelStatement::Set(var_ref, expression, range) => (
StmtKind::Set( StmtKind::Set(var_ref.process(), expression.process()),
VariableReference(
mir::TypeKind::Vague(mir::VagueType::Unknown),
todo!(), // was name.clone()
(*range).into(),
),
expression.process(),
),
*range, *range,
), ),
ast::BlockLevelStatement::Import { _i } => todo!(), ast::BlockLevelStatement::Import { _i } => todo!(),
@ -117,10 +110,36 @@ impl From<ast::ReturnType> for mir::ReturnKind {
} }
} }
impl ast::VariableReference {
fn process(&self) -> mir::IndexedVariableReference {
mir::IndexedVariableReference {
kind: self.0.process(),
meta: self.1.into(),
}
}
}
impl ast::VariableReferenceKind {
fn process(&self) -> mir::IndexedVariableReferenceKind {
match &self {
ast::VariableReferenceKind::Name(name, range) => {
mir::IndexedVariableReferenceKind::Named(NamedVariableRef(
mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(),
(*range).into(),
))
}
ast::VariableReferenceKind::Index(var_ref, idx) => {
mir::IndexedVariableReferenceKind::Index(Box::new(var_ref.process()), *idx)
}
}
}
}
impl ast::Expression { impl ast::Expression {
fn process(&self) -> mir::Expression { fn process(&self) -> mir::Expression {
let kind = match &self.0 { let kind = match &self.0 {
ast::ExpressionKind::VariableName(name) => mir::ExprKind::Variable(VariableReference( ast::ExpressionKind::VariableName(name) => mir::ExprKind::Variable(NamedVariableRef(
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(), name.clone(),
self.1.into(), self.1.into(),
@ -149,8 +168,12 @@ impl ast::Expression {
}; };
mir::ExprKind::If(mir::IfExpression(Box::new(cond), then_block, else_block)) mir::ExprKind::If(mir::IfExpression(Box::new(cond), then_block, else_block))
} }
ast::ExpressionKind::Array(expressions) => todo!(), ast::ExpressionKind::Array(expressions) => {
ast::ExpressionKind::Index(expression, _) => todo!(), mir::ExprKind::Array(expressions.iter().map(|e| e.process()).collect())
}
ast::ExpressionKind::Index(expression, idx) => {
mir::ExprKind::Index(Box::new(expression.process()), *idx)
}
}; };
mir::Expression(kind, self.1.into()) mir::Expression(kind, self.1.into())
@ -197,7 +220,9 @@ impl From<ast::TypeKind> for mir::TypeKind {
ast::TypeKind::U32 => mir::TypeKind::U32, ast::TypeKind::U32 => mir::TypeKind::U32,
ast::TypeKind::U64 => mir::TypeKind::U64, ast::TypeKind::U64 => mir::TypeKind::U64,
ast::TypeKind::U128 => mir::TypeKind::U128, ast::TypeKind::U128 => mir::TypeKind::U128,
ast::TypeKind::Array(type_kind, length) => todo!(), ast::TypeKind::Array(type_kind, length) => {
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
}
} }
} }
} }

View File

@ -5,7 +5,7 @@ use reid_lib::{
TerminatorKind as Term, Type, TerminatorKind as Term, Type,
}; };
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference}; use crate::mir::{self, types::ReturnType, NamedVariableRef, TypeKind};
/// Context that contains all of the given modules as complete codegenerated /// Context that contains all of the given modules as complete codegenerated
/// LLIR that can then be finally compiled into LLVM IR. /// LLIR that can then be finally compiled into LLVM IR.
@ -156,7 +156,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
impl mir::Statement { impl mir::Statement {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
match &self.0 { match &self.0 {
mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => { mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
let value = expression.codegen(scope).unwrap(); let value = expression.codegen(scope).unwrap();
scope.stack_values.insert( scope.stack_values.insert(
name.clone(), name.clone(),
@ -178,19 +178,20 @@ impl mir::Statement {
None None
} }
mir::StmtKind::Set(var, val) => { mir::StmtKind::Set(var, val) => {
if let Some(StackValue(kind, _)) = scope.stack_values.get(&var.1).cloned() { todo!("Re-think how set needs to work with arrays");
match kind { // if let Some(StackValue(kind, _)) = scope.stack_values.get(&var.1).cloned() {
StackValueKind::Immutable(_) => { // match kind {
panic!("Tried to mutate an immutable variable") // StackValueKind::Immutable(_) => {
} // panic!("Tried to mutate an immutable variable")
StackValueKind::Mutable(ptr) => { // }
let expression = val.codegen(scope).unwrap(); // StackValueKind::Mutable(ptr) => {
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap()) // let expression = val.codegen(scope).unwrap();
} // Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
} // }
} else { // }
panic!("") // } else {
} // panic!("")
// }
} }
// mir::StmtKind::If(if_expression) => if_expression.codegen(scope), // mir::StmtKind::If(if_expression) => if_expression.codegen(scope),
mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Import(_) => todo!(),
@ -333,6 +334,8 @@ impl mir::Expression {
None None
} }
} }
mir::ExprKind::Index(expression, _) => todo!("codegen for index expression"),
mir::ExprKind::Array(expressions) => todo!("codegen for array expression"),
} }
} }
} }
@ -413,6 +416,7 @@ impl TypeKind {
TypeKind::Bool => Type::Bool, TypeKind::Bool => Type::Bool,
TypeKind::Void => panic!("Void not a supported type"), TypeKind::Void => panic!("Void not a supported type"),
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"), TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
TypeKind::Array(_, _) => todo!("codegen for array type"),
} }
} }
} }

View File

@ -122,12 +122,33 @@ impl Display for Expression {
impl Display for ExprKind { impl Display for ExprKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Variable(var) => Display::fmt(var, f), ExprKind::Variable(var) => Display::fmt(var, f),
Self::Literal(lit) => Display::fmt(lit, f), ExprKind::Literal(lit) => Display::fmt(lit, f),
Self::BinOp(op, lhs, rhs) => write!(f, "{} {} {}", lhs, op, rhs), ExprKind::BinOp(op, lhs, rhs) => write!(f, "{} {} {}", lhs, op, rhs),
Self::FunctionCall(fc) => Display::fmt(fc, f), ExprKind::FunctionCall(fc) => Display::fmt(fc, f),
Self::If(if_exp) => Display::fmt(&if_exp, f), ExprKind::If(if_exp) => Display::fmt(&if_exp, f),
Self::Block(block) => Display::fmt(block, f), ExprKind::Block(block) => Display::fmt(block, f),
ExprKind::Index(expression, idx) => {
Display::fmt(&expression, f)?;
write_index(f, *idx)
}
ExprKind::Array(expressions) => {
f.write_char('[')?;
let mut state = Default::default();
let mut inner_f = PadAdapter::wrap(f, &mut state);
let mut iter = expressions.iter();
if let Some(item) = iter.next() {
write!(inner_f, "\n{}", item)?;
while let Some(item) = iter.next() {
writeln!(inner_f, ",")?;
write!(inner_f, "{}", item)?;
}
writeln!(inner_f, "")?;
}
f.write_char(']')
}
} }
} }
} }
@ -156,12 +177,24 @@ impl Display for FunctionCall {
} }
} }
impl Display for VariableReference { impl Display for NamedVariableRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "v(\"{}\", {})", &self.1, &self.0) write!(f, "v(\"{}\", {})", &self.1, &self.0)
} }
} }
impl Display for IndexedVariableReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.kind {
IndexedVariableReferenceKind::Named(name) => Display::fmt(name, f),
IndexedVariableReferenceKind::Index(variable_reference_kind, idx) => {
Display::fmt(&variable_reference_kind, f)?;
write_index(f, *idx)
}
}
}
}
impl Display for Literal { impl Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -211,3 +244,9 @@ impl Display for Metadata {
write!(f, "{:?}", self.range) write!(f, "{:?}", self.range)
} }
} }
fn write_index(f: &mut std::fmt::Formatter<'_>, idx: u64) -> std::fmt::Result {
f.write_char('[')?;
Display::fmt(&idx, f)?;
f.write_char(']')
}

View File

@ -32,7 +32,7 @@ impl From<TokenRange> for Metadata {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum TypeKind { pub enum TypeKind {
#[error("bool")] #[error("bool")]
Bool, Bool,
@ -58,6 +58,8 @@ pub enum TypeKind {
U128, U128,
#[error("void")] #[error("void")]
Void, Void,
#[error("[{0}; {1}]")]
Array(Box<TypeKind>, u64),
#[error(transparent)] #[error(transparent)]
Vague(#[from] VagueType), Vague(#[from] VagueType),
} }
@ -77,7 +79,7 @@ impl TypeKind {
if let TypeKind::Vague(vague) = self { if let TypeKind::Vague(vague) = self {
Err(*vague) Err(*vague)
} else { } else {
Ok(*self) Ok(self.clone())
} }
} }
} }
@ -98,6 +100,7 @@ impl TypeKind {
TypeKind::U32 => false, TypeKind::U32 => false,
TypeKind::U64 => false, TypeKind::U64 => false,
TypeKind::U128 => false, TypeKind::U128 => false,
TypeKind::Array(_, _) => false,
} }
} }
@ -117,6 +120,7 @@ impl TypeKind {
Bool => true, Bool => true,
Vague(_) => false, Vague(_) => false,
Void => false, Void => false,
Array(_, _) => false,
} }
} }
} }
@ -196,14 +200,16 @@ pub enum ReturnKind {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct VariableReference(pub TypeKind, pub String, pub Metadata); pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
#[derive(Debug)] #[derive(Debug)]
pub struct Import(pub String, pub Metadata); pub struct Import(pub String, pub Metadata);
#[derive(Debug)] #[derive(Debug)]
pub enum ExprKind { pub enum ExprKind {
Variable(VariableReference), Variable(NamedVariableRef),
Index(Box<Expression>, u64),
Array(Vec<Expression>),
Literal(Literal), Literal(Literal),
BinOp(BinaryOperator, Box<Expression>, Box<Expression>), BinOp(BinaryOperator, Box<Expression>, Box<Expression>),
FunctionCall(FunctionCall), FunctionCall(FunctionCall),
@ -267,11 +273,23 @@ pub struct Block {
#[derive(Debug)] #[derive(Debug)]
pub struct Statement(pub StmtKind, pub Metadata); pub struct Statement(pub StmtKind, pub Metadata);
#[derive(Debug)]
pub struct IndexedVariableReference {
pub kind: IndexedVariableReferenceKind,
pub meta: Metadata,
}
#[derive(Debug)]
pub enum IndexedVariableReferenceKind {
Named(NamedVariableRef),
Index(Box<IndexedVariableReference>, u64),
}
#[derive(Debug)] #[derive(Debug)]
pub enum StmtKind { pub enum StmtKind {
/// Variable name++mutability+type, evaluation /// Variable name++mutability+type, evaluation
Let(VariableReference, bool, Expression), Let(NamedVariableRef, bool, Expression),
Set(VariableReference, Expression), Set(IndexedVariableReference, Expression),
Import(Import), Import(Import),
Expression(Expression), Expression(Expression),
} }

View File

@ -2,6 +2,7 @@
//! passes. Passes can be performed on Reid MIR to e.g. typecheck the code. //! passes. Passes can be performed on Reid MIR to e.g. typecheck the code.
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::Infallible;
use std::error::Error as STDError; use std::error::Error as STDError;
use super::*; use super::*;
@ -129,7 +130,7 @@ impl Scope {
Scope { Scope {
function_returns: self.function_returns.clone(), function_returns: self.function_returns.clone(),
variables: self.variables.clone(), variables: self.variables.clone(),
return_type_hint: self.return_type_hint, return_type_hint: self.return_type_hint.clone(),
} }
} }
} }
@ -166,6 +167,16 @@ impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> {
self.state.ok(result, meta) self.state.ok(result, meta)
} }
pub fn note_errors<TMeta: Into<Metadata> + Clone>(
&mut self,
errors: &Vec<TError>,
meta: TMeta,
) {
for error in errors {
self.ok::<_, Infallible>(Err(error.clone()), meta.clone().into());
}
}
pub fn inner(&mut self) -> PassState<TError> { pub fn inner(&mut self) -> PassState<TError> {
self.inner.push(self.scope.inner()); self.inner.push(self.scope.inner());
let scope = self.inner.last_mut().unwrap(); let scope = self.inner.last_mut().unwrap();
@ -211,8 +222,8 @@ impl Module {
.set( .set(
function.name.clone(), function.name.clone(),
ScopeFunction { ScopeFunction {
ret: function.return_type, ret: function.return_type.clone(),
params: function.parameters.iter().map(|v| v.1).collect(), params: function.parameters.iter().cloned().map(|v| v.1).collect(),
}, },
) )
.ok(); .ok();
@ -234,7 +245,7 @@ impl FunctionDefinition {
.set( .set(
param.0.clone(), param.0.clone(),
ScopeVariable { ScopeVariable {
ty: param.1, ty: param.1.clone(),
mutable: false, mutable: false,
}, },
) )
@ -245,7 +256,7 @@ impl FunctionDefinition {
match &mut self.kind { match &mut self.kind {
FunctionDefinitionKind::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
scope.return_type_hint = Some(self.return_type); scope.return_type_hint = Some(self.return_type.clone());
block.pass(pass, state, scope); block.pass(pass, state, scope);
} }
FunctionDefinitionKind::Extern => {} FunctionDefinitionKind::Extern => {}
@ -289,7 +300,7 @@ impl Statement {
.set( .set(
variable_reference.1.clone(), variable_reference.1.clone(),
ScopeVariable { ScopeVariable {
ty: variable_reference.0, ty: variable_reference.0.clone(),
mutable: *mutable, mutable: *mutable,
}, },
) )

View File

@ -40,6 +40,10 @@ pub enum ErrorKind {
TypeNotInferrable(TypeKind), TypeNotInferrable(TypeKind),
#[error("Expected branch type to be {0}, found {1} instead")] #[error("Expected branch type to be {0}, found {1} instead")]
BranchTypesDiffer(TypeKind, TypeKind), BranchTypesDiffer(TypeKind, TypeKind),
#[error("Attempted to index a non-array type of {0}")]
TriedIndexingNonArray(TypeKind),
#[error("Index {0} out of bounds ({1})")]
IndexOutOfBounds(u64, u64),
} }
/// Struct used to implement a type-checking pass that can be performed on the /// Struct used to implement a type-checking pass that can be performed on the
@ -84,8 +88,8 @@ impl FunctionDefinition {
let return_type = self.return_type.clone(); let return_type = self.return_type.clone();
let inferred = match &mut self.kind { let inferred = match &mut self.kind {
FunctionDefinitionKind::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = Some(self.return_type); state.scope.return_type_hint = Some(self.return_type.clone());
block.typecheck(state, &hints, Some(return_type)) block.typecheck(state, &hints, Some(&return_type))
} }
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)), FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
}; };
@ -104,7 +108,7 @@ impl Block {
&mut self, &mut self,
state: &mut PassState<ErrorKind>, state: &mut PassState<ErrorKind>,
hints: &TypeRefs, hints: &TypeRefs,
hint_t: Option<TypeKind>, hint_t: Option<&TypeKind>,
) -> Result<TypeKind, ErrorKind> { ) -> Result<TypeKind, ErrorKind> {
let mut state = state.inner(); let mut state = state.inner();
@ -117,7 +121,7 @@ impl Block {
let var_t_resolved = variable_reference.0.resolve_hinted(&hints); let var_t_resolved = variable_reference.0.resolve_hinted(&hints);
// Typecheck (and coerce) expression with said type // Typecheck (and coerce) expression with said type
let res = expression.typecheck(&mut state, &hints, Some(var_t_resolved)); let res = expression.typecheck(&mut state, &hints, Some(&var_t_resolved));
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
// Unknown and note error. // Unknown and note error.
@ -136,7 +140,7 @@ impl Block {
state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2); state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
// Re-typecheck and coerce expression to default type // Re-typecheck and coerce expression to default type
let expr_res = expression.typecheck(&mut state, &hints, Some(res_t)); let expr_res = expression.typecheck(&mut state, &hints, Some(&res_t));
state.ok(expr_res, expression.1); state.ok(expr_res, expression.1);
res_t res_t
@ -154,7 +158,7 @@ impl Block {
.set( .set(
variable_reference.1.clone(), variable_reference.1.clone(),
ScopeVariable { ScopeVariable {
ty: variable_reference.0, ty: variable_reference.0.clone(),
mutable: *mutable, mutable: *mutable,
}, },
) )
@ -165,40 +169,41 @@ impl Block {
None None
} }
StmtKind::Set(variable_reference, expression) => { StmtKind::Set(variable_reference, expression) => {
if let Some(var) = state.scope.variables.get(&variable_reference.1).cloned() { todo!("Re-think how set needs to work with arrays")
// Typecheck expression and coerce to variable type // if let Some(var) = state.scope.variables.get(&variable_reference.1).cloned() {
let res = expression.typecheck(&mut state, &hints, Some(var.ty)); // // Typecheck expression and coerce to variable type
// let res = expression.typecheck(&mut state, &hints, Some(&var.ty));
// If expression resolution itself was erronous, resolve as // // If expression resolution itself was erronous, resolve as
// Unknown. // // Unknown.
let expr_ty = state.or_else(res, Vague(Unknown), expression.1); // let expr_ty = state.or_else(res, Vague(Unknown), expression.1);
// Make sure the expression and variable type to really // // Make sure the expression and variable type to really
// be the same // // be the same
let res_t = state.or_else( // let res_t = state.or_else(
expr_ty.collapse_into(&variable_reference.0.resolve_hinted(&hints)), // expr_ty.collapse_into(&variable_reference.0.resolve_hinted(&hints)),
Vague(Unknown), // Vague(Unknown),
variable_reference.2 + expression.1, // variable_reference.2 + expression.1,
); // );
// Update typing to be more accurate // // Update typing to be more accurate
variable_reference.0 = res_t; // variable_reference.0 = res_t;
if !var.mutable { // if !var.mutable {
state.ok::<_, Infallible>( // state.ok::<_, Infallible>(
Err(ErrorKind::VariableNotMutable(variable_reference.1.clone())), // Err(ErrorKind::VariableNotMutable(variable_reference.1.clone())),
variable_reference.2, // variable_reference.2,
); // );
} // }
None // None
} else { // } else {
state.ok::<_, Infallible>( // state.ok::<_, Infallible>(
Err(ErrorKind::VariableNotDefined(variable_reference.1.clone())), // Err(ErrorKind::VariableNotDefined(variable_reference.1.clone())),
variable_reference.2, // variable_reference.2,
); // );
None // None
} // }
} }
StmtKind::Import(_) => todo!(), // TODO StmtKind::Import(_) => todo!(), // TODO
StmtKind::Expression(expression) => { StmtKind::Expression(expression) => {
@ -221,18 +226,18 @@ impl Block {
// as to not cause problems in codegen later (when unable to delete the // as to not cause problems in codegen later (when unable to delete the
// block) // block)
if let Some((ReturnKind::Hard, expr)) = early_return { if let Some((ReturnKind::Hard, expr)) = early_return {
let hint = state.scope.return_type_hint; let hint = state.scope.return_type_hint.clone();
let res = expr.typecheck(&mut state, &hints, hint); let res = expr.typecheck(&mut state, &hints, hint.as_ref());
return Ok(state.or_else(res, Vague(Unknown), expr.1)); return Ok(state.or_else(res, Vague(Unknown), expr.1));
} }
if let Some((return_kind, expr)) = &mut self.return_expression { if let Some((return_kind, expr)) = &mut self.return_expression {
// Use function return type as hint if return is hard. // Use function return type as hint if return is hard.
let ret_hint_t = match return_kind { let ret_hint_t = match return_kind {
ReturnKind::Hard => state.scope.return_type_hint, ReturnKind::Hard => state.scope.return_type_hint.clone(),
ReturnKind::Soft => hint_t, ReturnKind::Soft => hint_t.cloned(),
}; };
let res = expr.typecheck(&mut state, &hints, ret_hint_t); let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
Ok(state.or_else(res, Vague(Unknown), expr.1)) Ok(state.or_else(res, Vague(Unknown), expr.1))
} else { } else {
Ok(Void) Ok(Void)
@ -245,7 +250,7 @@ impl Expression {
&mut self, &mut self,
state: &mut PassState<ErrorKind>, state: &mut PassState<ErrorKind>,
hints: &TypeRefs, hints: &TypeRefs,
hint_t: Option<TypeKind>, hint_t: Option<&TypeKind>,
) -> Result<TypeKind, ErrorKind> { ) -> Result<TypeKind, ErrorKind> {
match &mut self.0 { match &mut self.0 {
ExprKind::Variable(var_ref) => { ExprKind::Variable(var_ref) => {
@ -268,10 +273,10 @@ impl Expression {
var_ref.2, var_ref.2,
); );
Ok(var_ref.0) Ok(var_ref.0.clone())
} }
ExprKind::Literal(literal) => { ExprKind::Literal(literal) => {
*literal = literal.try_coerce(hint_t)?; *literal = literal.try_coerce(hint_t.cloned())?;
Ok(literal.as_type()) Ok(literal.as_type())
} }
ExprKind::BinOp(op, lhs, rhs) => { ExprKind::BinOp(op, lhs, rhs) => {
@ -279,13 +284,13 @@ impl Expression {
// operation once relevant // operation once relevant
let lhs_res = lhs.typecheck(state, &hints, None); let lhs_res = lhs.typecheck(state, &hints, None);
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1); let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1);
let rhs_res = rhs.typecheck(state, &hints, Some(lhs_type)); let rhs_res = rhs.typecheck(state, &hints, Some(&lhs_type));
let rhs_type = state.or_else(rhs_res, Vague(Unknown), rhs.1); let rhs_type = state.or_else(rhs_res, Vague(Unknown), rhs.1);
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) { if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
// Try to coerce both sides again with collapsed type // Try to coerce both sides again with collapsed type
lhs.typecheck(state, &hints, Some(collapsed)).ok(); lhs.typecheck(state, &hints, Some(&collapsed)).ok();
rhs.typecheck(state, &hints, Some(collapsed)).ok(); rhs.typecheck(state, &hints, Some(&collapsed)).ok();
} }
let both_t = lhs_type.collapse_into(&rhs_type)?; let both_t = lhs_type.collapse_into(&rhs_type)?;
@ -322,7 +327,7 @@ impl Expression {
function_call.parameters.iter_mut().zip(true_params_iter) function_call.parameters.iter_mut().zip(true_params_iter)
{ {
// Typecheck every param separately // Typecheck every param separately
let param_res = param.typecheck(state, &hints, Some(true_param_t)); let param_res = param.typecheck(state, &hints, Some(&true_param_t));
let param_t = state.or_else(param_res, Vague(Unknown), param.1); let param_t = state.or_else(param_res, Vague(Unknown), param.1);
state.ok(param_t.collapse_into(&true_param_t), param.1); state.ok(param_t.collapse_into(&true_param_t), param.1);
} }
@ -333,14 +338,14 @@ impl Expression {
.ret .ret
.collapse_into(&function_call.return_type.resolve_hinted(hints))?; .collapse_into(&function_call.return_type.resolve_hinted(hints))?;
// Update typing to be more accurate // Update typing to be more accurate
function_call.return_type = ret_t; function_call.return_type = ret_t.clone();
Ok(ret_t) Ok(ret_t)
} else { } else {
Ok(function_call.return_type) Ok(function_call.return_type.clone())
} }
} }
ExprKind::If(IfExpression(cond, lhs, rhs)) => { ExprKind::If(IfExpression(cond, lhs, rhs)) => {
let cond_res = cond.typecheck(state, &hints, Some(Bool)); let cond_res = cond.typecheck(state, &hints, Some(&Bool));
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1); let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
state.ok(cond_t.collapse_into(&Bool), cond.1); state.ok(cond_t.collapse_into(&Bool), cond.1);
@ -364,8 +369,8 @@ impl Expression {
if let Some(rhs) = rhs { if let Some(rhs) = rhs {
// If rhs existed, typecheck both sides to perform type // If rhs existed, typecheck both sides to perform type
// coercion. // coercion.
let lhs_res = lhs.typecheck(state, &hints, Some(collapsed)); let lhs_res = lhs.typecheck(state, &hints, Some(&collapsed));
let rhs_res = rhs.typecheck(state, &hints, Some(collapsed)); let rhs_res = rhs.typecheck(state, &hints, Some(&collapsed));
state.ok(lhs_res, lhs.meta); state.ok(lhs_res, lhs.meta);
state.ok(rhs_res, rhs.meta); state.ok(rhs_res, rhs.meta);
} }
@ -373,6 +378,42 @@ impl Expression {
Ok(collapsed) Ok(collapsed)
} }
ExprKind::Block(block) => block.typecheck(state, &hints, hint_t), ExprKind::Block(block) => block.typecheck(state, &hints, hint_t),
ExprKind::Index(expression, idx) => {
let expr_t = expression.typecheck(state, hints, hint_t)?;
if let TypeKind::Array(elem_t, len) = expr_t {
if len >= *idx {
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
}
Ok(*elem_t)
} else {
Err(ErrorKind::TriedIndexingNonArray(expr_t))
}
}
ExprKind::Array(expressions) => {
let mut expr_result = try_all(
expressions
.iter_mut()
.map(|e| e.typecheck(state, hints, hint_t))
.collect(),
);
match &mut expr_result {
Ok(expr_types) => {
let mut iter = expr_types.iter_mut();
if let Some(first) = iter.next() {
for other in iter {
state.ok(first.collapse_into(other), self.1);
}
Ok(first.clone())
} else {
Ok(Array(Box::new(Void), 0))
}
}
Err(errors) => {
state.note_errors(errors, self.1);
Ok(Array(Box::new(Vague(Unknown)), expressions.len() as u64))
}
}
}
} }
} }
} }
@ -381,7 +422,7 @@ impl Literal {
/// Try to coerce this literal, ie. convert it to a more specific type in /// Try to coerce this literal, ie. convert it to a more specific type in
/// regards to the given hint if any. /// regards to the given hint if any.
fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> { fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
if let Some(hint) = hint { if let Some(hint) = &hint {
use Literal as L; use Literal as L;
use VagueLiteral as VagueL; use VagueLiteral as VagueL;
Ok(match (self, hint) { Ok(match (self, hint) {
@ -409,7 +450,7 @@ impl Literal {
(L::Vague(VagueL::Number(v)), U64) => L::U64(v as u64), (L::Vague(VagueL::Number(v)), U64) => L::U64(v as u64),
(L::Vague(VagueL::Number(v)), U128) => L::U128(v as u128), (L::Vague(VagueL::Number(v)), U128) => L::U128(v as u128),
(_, Vague(_)) => self, (_, Vague(_)) => self,
_ => Err(ErrorKind::LiteralIncompatible(self, hint))?, _ => Err(ErrorKind::LiteralIncompatible(self, hint.clone()))?,
}) })
} else { } else {
Ok(self) Ok(self)
@ -428,19 +469,19 @@ impl TypeKind {
/// Error if not. /// Error if not.
fn or_default(&self) -> Result<TypeKind, ErrorKind> { fn or_default(&self) -> Result<TypeKind, ErrorKind> {
match self { match self {
Vague(vague_type) => match vague_type { Vague(vague_type) => match &vague_type {
Unknown => Err(ErrorKind::TypeIsVague(*vague_type)), Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
Number => Ok(TypeKind::I32), Number => Ok(TypeKind::I32),
TypeRef(_) => panic!("Hinted default!"), TypeRef(_) => panic!("Hinted default!"),
}, },
_ => Ok(*self), _ => Ok(self.clone()),
} }
} }
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind { fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
match self { match self {
Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(), Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
_ => *self, _ => self.clone(),
} }
} }
} }
@ -461,11 +502,11 @@ impl Collapsable for TypeKind {
(Vague(Number), other) | (other, Vague(Number)) => match other { (Vague(Number), other) | (other, Vague(Number)) => match other {
Vague(Unknown) => Ok(Vague(Number)), Vague(Unknown) => Ok(Vague(Number)),
Vague(Number) => Ok(Vague(Number)), Vague(Number) => Ok(Vague(Number)),
I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => Ok(*other), I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(*self, *other)), _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}, },
(Vague(Unknown), other) | (other, Vague(Unknown)) => Ok(other.clone()), (Vague(Unknown), other) | (other, Vague(Unknown)) => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(*self, *other)), _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
} }
} }
} }

View File

@ -4,7 +4,9 @@
//! must then be passed through TypeCheck with the same [`TypeRefs`] in order to //! must then be passed through TypeCheck with the same [`TypeRefs`] in order to
//! place the correct types from the IDs and check that there are no issues. //! place the correct types from the IDs and check that there are no issues.
use std::iter; use std::{convert::Infallible, iter};
use crate::{mir::TypeKind, util::try_all};
use super::{ use super::{
pass::{Pass, PassState, ScopeVariable}, pass::{Pass, PassState, ScopeVariable},
@ -59,7 +61,7 @@ impl FunctionDefinition {
match &mut self.kind { match &mut self.kind {
FunctionDefinitionKind::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = Some(self.return_type); state.scope.return_type_hint = Some(self.return_type.clone());
let scope_hints = ScopeTypeRefs::from(type_refs); let scope_hints = ScopeTypeRefs::from(type_refs);
// Infer block return type // Infer block return type
@ -91,7 +93,7 @@ impl Block {
StmtKind::Let(var, mutable, expr) => { StmtKind::Let(var, mutable, expr) => {
// Get the TypeRef for this variable declaration // Get the TypeRef for this variable declaration
let mut var_ref = let mut var_ref =
state.ok(inner_hints.new_var(var.1.clone(), *mutable, var.0), var.2); state.ok(inner_hints.new_var(var.1.clone(), *mutable, &var.0), var.2);
// If ok, update the MIR type to this TypeRef // If ok, update the MIR type to this TypeRef
if let Some(var_ref) = &var_ref { if let Some(var_ref) = &var_ref {
@ -111,23 +113,24 @@ impl Block {
} }
} }
StmtKind::Set(var, expr) => { StmtKind::Set(var, expr) => {
// Get the TypeRef for this variable declaration todo!("Re-think how set needs to work with arrays")
let var_ref = inner_hints.find_hint(&var.1); // // Get the TypeRef for this variable declaration
// let var_ref = inner_hints.find_hint(&var.1);
// If ok, update the MIR type to this TypeRef // // If ok, update the MIR type to this TypeRef
if let Some((_, var_ref)) = &var_ref { // if let Some((_, var_ref)) = &var_ref {
var.0 = var_ref.as_type() // var.0 = var_ref.as_type()
} // }
// Infer hints for the expression itself // // Infer hints for the expression itself
let inferred = expr.infer_types(&mut state, &inner_hints); // let inferred = expr.infer_types(&mut state, &inner_hints);
let expr_ty_ref = state.ok(inferred, expr.1); // let expr_ty_ref = state.ok(inferred, expr.1);
// Try to narrow the variable type declaration with the // // Try to narrow the variable type declaration with the
// expression // // expression
if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) { // if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) {
var_ref.narrow(&expr_ty_ref); // var_ref.narrow(&expr_ty_ref);
} // }
} }
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(expr) => { StmtKind::Expression(expr) => {
@ -149,7 +152,7 @@ impl Block {
// Narow return type to declared type if hard return // Narow return type to declared type if hard return
if kind == ReturnKind::Hard { if kind == ReturnKind::Hard {
if let Some(hint) = state.scope.return_type_hint { if let Some(hint) = &state.scope.return_type_hint {
ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap()); ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap());
} }
} }
@ -260,6 +263,52 @@ impl Expression {
ReturnKind::Soft => Ok(block_ref.1), ReturnKind::Soft => Ok(block_ref.1),
} }
} }
ExprKind::Index(expression, _) => {
let expr_ty = expression.infer_types(state, type_refs)?;
let kind = unsafe { expr_ty.resolve_type() };
match kind {
Array(type_kind, _) => Ok(type_refs.from_type(&type_kind).unwrap()),
_ => Err(ErrorKind::TriedIndexingNonArray(kind)),
}
}
ExprKind::Array(expressions) => {
let mut expr_types_result = try_all(
expressions
.iter_mut()
.map(|e| (*e).infer_types(state, type_refs))
.collect(),
);
match &mut expr_types_result {
Ok(expr_types) => {
let mut iter = expr_types.iter_mut();
if let Some(first) = iter.next() {
while let Some(other) = iter.next() {
first.narrow(other);
}
Ok(type_refs
.from_type(&Array(
Box::new(first.as_type()),
expressions.len() as u64,
))
.unwrap())
} else {
Ok(type_refs
.from_type(&Array(Box::new(TypeKind::Void), 0))
.unwrap())
}
}
Err(errors) => {
state.note_errors(errors, self.1);
Ok(type_refs
.from_type(&TypeKind::Array(
Box::new(TypeKind::Vague(Unknown)),
expressions.len() as u64,
))
.unwrap())
}
}
}
} }
} }
} }

View File

@ -14,7 +14,14 @@ pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>);
impl<'scope> TypeRef<'scope> { impl<'scope> TypeRef<'scope> {
pub unsafe fn resolve_type(&self) -> TypeKind { pub unsafe fn resolve_type(&self) -> TypeKind {
unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) } unsafe {
self.1
.types
.hints
.borrow()
.get_unchecked(*self.0.borrow())
.clone()
}
} }
pub fn narrow(&mut self, other: &TypeRef) -> Option<TypeRef<'scope>> { pub fn narrow(&mut self, other: &TypeRef) -> Option<TypeRef<'scope>> {
@ -46,15 +53,15 @@ pub struct TypeRefs {
} }
impl TypeRefs { impl TypeRefs {
pub fn new(&self, ty: TypeKind) -> TypeIdRef { pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
let idx = self.hints.borrow().len(); let idx = self.hints.borrow().len();
let typecell = Rc::new(RefCell::new(idx)); let typecell = Rc::new(RefCell::new(idx));
self.type_refs.borrow_mut().push(typecell.clone()); self.type_refs.borrow_mut().push(typecell.clone());
self.hints.borrow_mut().push(ty); self.hints.borrow_mut().push(ty.clone());
typecell typecell
} }
pub fn find(&self, ty: TypeKind) -> Option<TypeIdRef> { pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> {
if ty.known().is_err() { if ty.known().is_err() {
// Only do this for non-vague types that can not be further narrowed // Only do this for non-vague types that can not be further narrowed
// down. // down.
@ -66,7 +73,7 @@ impl TypeRefs {
.borrow_mut() .borrow_mut()
.iter() .iter()
.enumerate() .enumerate()
.find(|(_, t)| **t == ty) .find(|(_, t)| *t == ty)
.map(|(i, _)| i) .map(|(i, _)| i)
{ {
Some(Rc::new(RefCell::new(idx))) Some(Rc::new(RefCell::new(idx)))
@ -89,7 +96,7 @@ impl TypeRefs {
pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> { pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> {
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
self.hints.borrow().get(inner_idx).copied() self.hints.borrow().get(inner_idx).cloned()
} }
} }
@ -114,7 +121,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
&'outer self, &'outer self,
name: String, name: String,
mutable: bool, mutable: bool,
initial_ty: TypeKind, initial_ty: &TypeKind,
) -> Result<TypeRef<'outer>, ErrorKind> { ) -> Result<TypeRef<'outer>, ErrorKind> {
if self.variables.borrow().contains_key(&name) { if self.variables.borrow().contains_key(&name) {
return Err(ErrorKind::VariableAlreadyDefined(name)); return Err(ErrorKind::VariableAlreadyDefined(name));
@ -132,12 +139,17 @@ impl<'outer> ScopeTypeRefs<'outer> {
let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() }; let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() };
self.types.type_refs.borrow().get(inner_idx).cloned()? self.types.type_refs.borrow().get(inner_idx).cloned()?
} }
TypeKind::Vague(_) => self.types.new(*ty), TypeKind::Vague(_) => self.types.new(ty),
TypeKind::Array(elem_ty, length) => {
let elem_ty = self.from_type(elem_ty)?;
self.types
.new(&TypeKind::Array(Box::new(elem_ty.as_type()), *length))
}
_ => { _ => {
if let Some(ty_ref) = self.types.find(*ty) { if let Some(ty_ref) = self.types.find(ty) {
ty_ref ty_ref
} else { } else {
self.types.new(*ty) self.types.new(ty)
} }
} }
}; };

View File

@ -1,3 +1,5 @@
use crate::ast::VariableReference;
use super::*; use super::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -7,6 +9,7 @@ pub enum ReturnTypeOther {
Set(Metadata), Set(Metadata),
EmptyBlock(Metadata), EmptyBlock(Metadata),
NoBlockReturn(Metadata), NoBlockReturn(Metadata),
IndexingNonArray(Metadata),
} }
impl TypeKind { impl TypeKind {
@ -15,10 +18,11 @@ impl TypeKind {
pub fn binop_type(&self, op: &BinaryOperator) -> TypeKind { pub fn binop_type(&self, op: &BinaryOperator) -> TypeKind {
// TODO make some type of mechanism that allows to binop two values of // TODO make some type of mechanism that allows to binop two values of
// differing types.. // differing types..
// TODO Return None for arrays later
match op { match op {
BinaryOperator::Add => *self, BinaryOperator::Add => self.clone(),
BinaryOperator::Minus => *self, BinaryOperator::Minus => self.clone(),
BinaryOperator::Mult => *self, BinaryOperator::Mult => self.clone(),
BinaryOperator::And => TypeKind::Bool, BinaryOperator::And => TypeKind::Bool,
BinaryOperator::Cmp(_) => TypeKind::Bool, BinaryOperator::Cmp(_) => TypeKind::Bool,
} }
@ -62,7 +66,7 @@ impl ReturnType for Statement {
), ),
Set(var, expr) => if_hard( Set(var, expr) => if_hard(
expr.return_type()?, expr.return_type()?,
Err(ReturnTypeOther::Set(var.2 + expr.1)), Err(ReturnTypeOther::Set(var.meta + expr.1)),
), ),
Import(_) => todo!(), Import(_) => todo!(),
Expression(expression) => expression.return_type(), Expression(expression) => expression.return_type(),
@ -85,6 +89,25 @@ impl ReturnType for Expression {
Block(block) => block.return_type(), Block(block) => block.return_type(),
FunctionCall(fcall) => fcall.return_type(), FunctionCall(fcall) => fcall.return_type(),
If(expr) => expr.return_type(), If(expr) => expr.return_type(),
Index(expression, _) => {
let expr_type = expression.return_type()?;
if let (_, TypeKind::Array(elem_ty, _)) = expr_type {
Ok((ReturnKind::Soft, *elem_ty))
} else {
Err(ReturnTypeOther::IndexingNonArray(expression.1))
}
}
Array(expressions) => {
let first = expressions
.iter()
.next()
.map(|e| e.return_type())
.unwrap_or(Ok((ReturnKind::Soft, TypeKind::Void)))?;
Ok((
ReturnKind::Soft,
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
))
}
} }
} }
} }
@ -107,7 +130,7 @@ impl ReturnType for IfExpression {
} }
} }
impl ReturnType for VariableReference { impl ReturnType for NamedVariableRef {
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> { fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
Ok((ReturnKind::Soft, self.0.clone())) Ok((ReturnKind::Soft, self.0.clone()))
} }

View File

@ -153,6 +153,13 @@ impl<'a, 'b> TokenStream<'a, 'b> {
end: self.position, end: self.position,
}) })
} }
pub fn get_one_token_range(&self) -> TokenRange {
TokenRange {
start: self.position - 1,
end: self.position,
}
}
} }
impl Drop for TokenStream<'_, '_> { impl Drop for TokenStream<'_, '_> {