Compare commits

...

8 Commits

14 changed files with 367 additions and 311 deletions

View File

@ -14,6 +14,8 @@
BINARY="$(echo $1 | cut -d'.' -f1)"".out"
echo $1
make clean SRC=$1 ; make SRC=$1 && echo ""
$BINARY ; echo "Return value: ""$?"

View File

@ -310,10 +310,12 @@ impl Builder {
Instr::ArrayAlloca(_, _) => Ok(()),
Instr::GetElemPtr(ptr_val, _) => {
let ptr_ty = ptr_val.get_type(&self)?;
if let Type::Ptr(_) = ptr_ty {
Ok(())
} else {
Err(()) // TODO error: not a pointer
match ptr_ty {
Type::CustomType(custom) => match self.type_data(&custom).kind {
CustomTypeKind::NamedStruct(_) => Ok(()),
},
Type::Ptr(_) => Ok(()),
_ => Err(()),
}
}
Instr::GetStructElemPtr(ptr_val, idx) => {

View File

@ -21,7 +21,7 @@ use llvm_sys::{
};
use crate::{
CustomTypeKind, NamedStruct,
CustomTypeKind,
builder::{TypeHolder, TypeValue},
util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring},
};
@ -496,20 +496,11 @@ impl InstructionHolder {
module.values.get(arr).unwrap().value_ref,
llvm_indices.as_mut_ptr(),
llvm_indices.len() as u32,
into_cstring(format!(
"array_gep_{:?}",
indices
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join("_")
))
.as_ptr(),
into_cstring(format!("array_gep")).as_ptr(),
)
}
GetStructElemPtr(struct_val, idx) => {
let t = struct_val.get_type(module.builder).unwrap();
dbg!(&t);
let Type::Ptr(struct_t) = t else { panic!() };
let type_fmt = if let Type::CustomType(type_val) = *struct_t {
@ -517,7 +508,6 @@ impl InstructionHolder {
} else {
format!("{:?}", struct_t)
};
dbg!(idx);
LLVMBuildStructGEP2(
module.builder_ref,

View File

@ -425,11 +425,21 @@ impl Parse for VariableReference {
stream.get_range().unwrap(),
);
while let Ok(ArrayValueIndex(idx)) = stream.parse() {
var_ref = VariableReference(
VariableReferenceKind::ArrayIndex(Box::new(var_ref), idx),
stream.get_range().unwrap(),
);
while let Ok(val) = stream.parse::<ValueIndex>() {
match val {
ValueIndex::Array(ArrayValueIndex(idx)) => {
var_ref = VariableReference(
VariableReferenceKind::ArrayIndex(Box::new(var_ref), idx),
stream.get_range().unwrap(),
);
}
ValueIndex::Struct(StructValueIndex(name)) => {
var_ref = VariableReference(
VariableReferenceKind::StructIndex(Box::new(var_ref), name),
stream.get_range().unwrap(),
);
}
}
}
Ok(var_ref)

View File

@ -2,7 +2,7 @@ use std::path::PathBuf;
use crate::{
ast::{self},
mir::{self, NamedVariableRef, StmtKind, StructType},
mir::{self, NamedVariableRef, StmtKind, StructField, StructType},
};
impl mir::Context {
@ -71,7 +71,13 @@ impl ast::Module {
mir::TypeDefinitionKind::Struct(StructType(
struct_definition_fields
.iter()
.map(|s| (s.name.clone(), s.ty.clone().into()))
.map(|s| {
StructField(
s.name.clone(),
s.ty.clone().into(),
s.range.into(),
)
})
.collect(),
))
}

View File

@ -8,7 +8,7 @@ use reid_lib::{
};
use crate::mir::{
self, types::ReturnType, IndexedVariableReference, NamedVariableRef, StructType,
self, types::ReturnType, IndexedVariableReference, NamedVariableRef, StructField, StructType,
TypeDefinitionKind, TypeKind,
};
@ -65,7 +65,7 @@ impl mir::Module {
// TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this
// will cause a panic!
.map(|(_, t)| t.get_type(&type_values))
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
.collect(),
)))
}
@ -80,14 +80,14 @@ impl mir::Module {
let param_types: Vec<Type> = function
.parameters
.iter()
.map(|(_, p)| p.get_type(&type_values))
.map(|(_, p)| p.get_type(&type_values, &types))
.collect();
let is_main = self.is_main && function.name == "main";
let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => module.function(
&function.name,
function.return_type.get_type(&type_values),
function.return_type.get_type(&type_values, &types),
param_types,
FunctionFlags {
is_pub: function.is_pub || is_main,
@ -98,7 +98,7 @@ impl mir::Module {
),
mir::FunctionDefinitionKind::Extern(imported) => module.function(
&function.name,
function.return_type.get_type(&type_values),
function.return_type.get_type(&type_values, &types),
param_types,
FunctionFlags {
is_extern: true,
@ -120,7 +120,7 @@ impl mir::Module {
p_name.clone(),
StackValue(
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
p_ty.get_type(&type_values),
p_ty.get_type(&type_values, &types),
),
);
}
@ -175,6 +175,22 @@ pub enum StackValueKind {
Mutable(InstructionValue),
}
impl StackValueKind {
unsafe fn get_instr(&self) -> &InstructionValue {
match self {
StackValueKind::Immutable(val) => val,
StackValueKind::Mutable(val) => val,
}
}
fn with_instr(&self, instr: InstructionValue) -> StackValueKind {
match self {
StackValueKind::Immutable(_) => StackValueKind::Immutable(instr),
StackValueKind::Mutable(_) => StackValueKind::Mutable(instr),
}
}
}
impl<'ctx, 'a> Scope<'ctx, 'a> {
fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
Scope {
@ -202,48 +218,6 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
}
}
impl IndexedVariableReference {
fn get_stack_value(&self, scope: &mut Scope) -> Option<(StackValue, Vec<u32>)> {
match &self.kind {
mir::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => scope
.stack_values
.get(name)
.cloned()
.map(|v| (v, Vec::new())),
mir::IndexedVariableReferenceKind::ArrayIndex(inner, idx) => {
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
match &inner_val.1 {
Type::Ptr(_) => {
indices.push(*idx as u32);
Some((inner_val, indices))
}
_ => panic!("Tried to codegen indexing a non-indexable value!"),
}
}
mir::IndexedVariableReferenceKind::StructIndex(inner, field) => {
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
let idx = if let Type::CustomType(ty_val) = inner_val.1 {
match scope.types.get(&ty_val).unwrap() {
TypeDefinitionKind::Struct(struct_type) => struct_type.find_index(field),
}
} else {
None
}?;
match &inner_val.1 {
Type::Ptr(_) => {
indices.push(idx as u32);
Some((inner_val, indices))
}
_ => panic!("Tried to codegen indexing a non-indexable value!"),
}
}
}
}
}
impl mir::Statement {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
match &self.0 {
@ -255,13 +229,22 @@ impl mir::Statement {
match mutable {
false => StackValueKind::Immutable(value),
true => match ty {
// Struct is already allocated at initialization
TypeKind::Array(_, _) => StackValueKind::Mutable(value),
TypeKind::CustomType(n) => match scope
.types
.get(scope.type_values.get(n).unwrap())
.unwrap()
{
// Struct also is allocated at initialization
TypeDefinitionKind::Struct(_) => StackValueKind::Mutable(value),
},
_ => StackValueKind::Mutable({
let alloca = scope
.block
.build(Instr::Alloca(
name.clone(),
ty.get_type(scope.type_values),
ty.get_type(scope.type_values, scope.types),
))
.unwrap();
scope.block.build(Instr::Store(alloca, value)).unwrap();
@ -269,30 +252,18 @@ impl mir::Statement {
}),
},
},
ty.get_type(scope.type_values),
ty.get_type(scope.type_values, scope.types),
),
);
None
}
mir::StmtKind::Set(var, val) => {
if let Some((StackValue(kind, mut ty), indices)) = var.get_stack_value(scope) {
if let Some(StackValue(kind, _)) = var.get_stack_value(scope, false) {
match kind {
StackValueKind::Immutable(_) => {
panic!("Tried to mutate an immutable variable")
}
StackValueKind::Mutable(mut ptr) => {
for (i, idx) in indices.iter().enumerate() {
let Type::Ptr(inner) = ty else { panic!() };
ty = *inner;
ptr = scope
.block
.build(Instr::GetElemPtr(ptr, vec![*idx]))
.unwrap();
if i < (indices.len() - 1) {
ptr = scope.block.build(Instr::Load(ptr, ty.clone())).unwrap()
}
}
StackValueKind::Mutable(ptr) => {
let expression = val.codegen(scope).unwrap();
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
}
@ -454,7 +425,10 @@ impl mir::Expression {
Some(
scope
.block
.build(Instr::Load(ptr, val_t.get_type(scope.type_values)))
.build(Instr::Load(
ptr,
val_t.get_type(scope.type_values, scope.types),
))
.unwrap(),
)
}
@ -472,7 +446,7 @@ impl mir::Expression {
let array = scope
.block
.build(Instr::ArrayAlloca(
instr_t.get_type(scope.type_values),
instr_t.get_type(scope.type_values, scope.types),
instr_list.len() as u32,
))
.unwrap();
@ -502,10 +476,14 @@ impl mir::Expression {
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
.unwrap();
dbg!(&type_kind.get_type(scope.type_values, scope.types));
Some(
scope
.block
.build(Instr::Load(ptr, type_kind.get_type(scope.type_values)))
.build(Instr::Load(
ptr,
type_kind.get_type(scope.type_values, scope.types),
))
.unwrap(),
)
}
@ -534,6 +512,85 @@ impl mir::Expression {
}
}
impl IndexedVariableReference {
fn get_stack_value(&self, scope: &mut Scope, load_after_gep: bool) -> Option<StackValue> {
match &self.kind {
mir::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
scope.stack_values.get(name).cloned().map(|v| v)
}
mir::IndexedVariableReferenceKind::ArrayIndex(inner, idx) => {
let inner_stack_val = inner.get_stack_value(scope, true)?;
let mut gep_instr = scope
.block
.build(Instr::GetElemPtr(
unsafe { *inner_stack_val.0.get_instr() },
vec![*idx as u32],
))
.unwrap();
match &inner_stack_val.1 {
Type::Ptr(inner_ty) => {
if load_after_gep {
gep_instr = scope
.block
.build(Instr::Load(gep_instr, *inner_ty.clone()))
.unwrap()
}
Some(StackValue(
inner_stack_val.0.with_instr(gep_instr),
*inner_ty.clone(),
))
}
_ => panic!("Tried to codegen indexing a non-indexable value!"),
}
}
mir::IndexedVariableReferenceKind::StructIndex(inner, field) => {
let inner_stack_val = inner.get_stack_value(scope, true)?;
let (instr_value, inner_ty) = if let Type::Ptr(inner_ty) = inner_stack_val.1 {
if let Type::CustomType(ty_val) = *inner_ty {
match scope.types.get(&ty_val).unwrap() {
TypeDefinitionKind::Struct(struct_type) => {
let idx = struct_type.find_index(field)?;
let field_ty = struct_type
.get_field_ty(field)?
.get_type(scope.type_values, scope.types);
let mut gep_instr = scope
.block
.build(Instr::GetStructElemPtr(
unsafe { *inner_stack_val.0.get_instr() },
idx,
))
.unwrap();
if load_after_gep {
gep_instr = scope
.block
.build(Instr::Load(gep_instr, field_ty.clone()))
.unwrap()
}
Some((gep_instr, field_ty))
}
}
} else {
None
}
} else {
None
}?;
Some(StackValue(
inner_stack_val.0.with_instr(instr_value),
Type::Ptr(Box::new(inner_ty)),
))
}
}
}
}
impl mir::CmpOperator {
fn int_predicate(&self) -> CmpPredicate {
match self {
@ -596,7 +653,11 @@ impl mir::Literal {
}
impl TypeKind {
fn get_type(&self, type_vals: &HashMap<String, TypeValue>) -> Type {
fn get_type(
&self,
type_vals: &HashMap<String, TypeValue>,
typedefs: &HashMap<TypeValue, TypeDefinitionKind>,
) -> Type {
match &self {
TypeKind::I8 => Type::I8,
TypeKind::I16 => Type::I16,
@ -610,10 +671,16 @@ impl TypeKind {
TypeKind::U128 => Type::U128,
TypeKind::Bool => Type::Bool,
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals))),
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals, typedefs))),
TypeKind::Void => Type::Void,
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
TypeKind::CustomType(n) => Type::CustomType(type_vals.get(n).unwrap().clone()),
TypeKind::CustomType(n) => {
let type_val = type_vals.get(n).unwrap().clone();
let custom_t = Type::CustomType(type_val);
match typedefs.get(&type_val).unwrap() {
TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)),
}
}
}
}
}

View File

@ -55,8 +55,8 @@ impl Display for TypeDefinitionKind {
writeln!(f)?;
let mut state = Default::default();
let mut inner_f = PadAdapter::wrap(f, &mut state);
for (field_name, field_ty) in &items.0 {
writeln!(inner_f, "{}: {:?},", field_name, field_ty)?;
for field in &items.0 {
writeln!(inner_f, "{},", field)?;
}
f.write_char('}')
}
@ -64,6 +64,12 @@ impl Display for TypeDefinitionKind {
}
}
impl Display for StructField {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {:?}", self.0, self.1)
}
}
impl Display for FunctionDefinition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(

View File

@ -82,20 +82,21 @@ pub enum VagueType {
}
#[derive(Clone, Debug)]
pub struct StructType(pub Vec<(String, TypeKind)>);
pub struct StructType(pub Vec<StructField>);
#[derive(Clone, Debug)]
pub struct StructField(pub String, pub TypeKind, pub Metadata);
impl StructType {
pub fn find_index(&self, name: &String) -> Option<u32> {
self.0
.iter()
.enumerate()
.find(|(_, (n, _))| n == name)
.find(|(_, StructField(n, _, _))| n == name)
.map(|(i, _)| i as u32)
}
}
pub type TypedefMap = HashMap<String, TypeDefinitionKind>;
impl TypeKind {
pub fn known(&self) -> Result<TypeKind, VagueType> {
if let TypeKind::Vague(vague) = self {
@ -106,55 +107,6 @@ impl TypeKind {
}
}
impl TypeKind {
pub fn signed(&self, typedefs: &TypedefMap) -> bool {
match self {
TypeKind::Void => false,
TypeKind::Vague(_) => false,
TypeKind::Bool => false,
TypeKind::I8 => false,
TypeKind::I16 => false,
TypeKind::I32 => false,
TypeKind::I64 => false,
TypeKind::I128 => false,
TypeKind::U8 => false,
TypeKind::U16 => false,
TypeKind::U32 => false,
TypeKind::U64 => false,
TypeKind::U128 => false,
TypeKind::StringPtr => false,
TypeKind::Array(_, _) => false,
TypeKind::CustomType(name) => match typedefs.get(name).unwrap() {
TypeDefinitionKind::Struct(_) => false,
},
}
}
pub fn is_maths(&self, typedefs: &TypedefMap) -> bool {
use TypeKind::*;
match &self {
I8 => true,
I16 => true,
I32 => true,
I64 => true,
I128 => true,
U8 => true,
U16 => true,
U32 => true,
U64 => true,
U128 => true,
Bool => true,
Vague(_) => false,
Void => false,
StringPtr => false,
Array(_, _) => false,
TypeKind::CustomType(name) => match typedefs.get(name).unwrap() {
TypeDefinitionKind::Struct(_) => false,
},
}
}
}
#[derive(Debug, Clone)]
pub enum Literal {
I8(i8),

View File

@ -33,9 +33,6 @@ impl<TErr: STDError> STDError for Error<TErr> {
}
}
#[derive(Clone, Debug)]
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
#[derive(Debug)]
pub struct State<TErr: STDError> {
pub errors: Vec<Error<TErr>>,
@ -84,6 +81,9 @@ impl<TErr: STDError> State<TErr> {
}
}
#[derive(Clone, Debug)]
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
impl<T: std::fmt::Debug> Default for Storage<T> {
fn default() -> Self {
Self(Default::default())
@ -114,18 +114,6 @@ pub struct Scope {
pub return_type_hint: Option<TypeKind>,
}
#[derive(Clone, Debug)]
pub struct ScopeFunction {
pub ret: TypeKind,
pub params: Vec<TypeKind>,
}
#[derive(Clone, Debug)]
pub struct ScopeVariable {
pub ty: TypeKind,
pub mutable: bool,
}
impl Scope {
pub fn inner(&self) -> Scope {
Scope {
@ -136,11 +124,26 @@ impl Scope {
}
}
pub fn get_typedefs(&self) -> &TypedefMap {
&self.types.0
pub fn get_struct_type(&self, name: &String) -> Option<&StructType> {
let ty = self.types.get(&name)?;
match ty {
TypeDefinitionKind::Struct(struct_ty) => Some(struct_ty),
}
}
}
#[derive(Clone, Debug)]
pub struct ScopeFunction {
pub ret: TypeKind,
pub params: Vec<TypeKind>,
}
#[derive(Clone, Debug)]
pub struct ScopeVariable {
pub ty: TypeKind,
pub mutable: bool,
}
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
state: &'st mut State<TError>,
pub scope: &'sc mut Scope,

View File

@ -71,7 +71,7 @@ fn check_typedefs_for_recursion<'a, 'b>(
) {
match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
for field_ty in fields.iter().map(|(_, ty)| ty) {
for field_ty in fields.iter().map(|StructField(_, ty, _)| ty) {
if let TypeKind::CustomType(name) = field_ty {
if seen.contains(name) {
state.ok::<_, Infallible>(
@ -103,11 +103,11 @@ impl<'t> Pass for TypeCheck<'t> {
match kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
let mut fieldmap = HashMap::new();
for (name, field_ty) in fields {
for StructField(name, field_ty, field_meta) in fields {
if let Some(_) = fieldmap.insert(name, field_ty) {
state.ok::<_, Infallible>(
Err(ErrorKind::DuplicateStructField(name.clone())),
meta.clone(),
field_meta.clone(),
);
}
}
@ -186,7 +186,7 @@ impl Block {
fn typecheck(
&mut self,
state: &mut PassState<ErrorKind>,
hints: &TypeRefs,
typerefs: &TypeRefs,
hint_t: Option<&TypeKind>,
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
let mut state = state.inner();
@ -197,10 +197,10 @@ impl Block {
let ret = match &mut statement.0 {
StmtKind::Let(variable_reference, mutable, expression) => {
// Resolve possible hint in var reference
let var_t_resolved = variable_reference.0.resolve_hinted(&hints);
let var_t_resolved = variable_reference.0.resolve_ref(&typerefs);
// Typecheck (and coerce) expression with said type
let res = expression.typecheck(&mut state, &hints, Some(&var_t_resolved));
let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved));
// If expression resolution itself was erronous, resolve as
// Unknown and note error.
@ -222,7 +222,7 @@ impl Block {
);
// 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, &typerefs, Some(&res_t));
state.ok(expr_res, expression.1);
res_t
@ -251,6 +251,9 @@ impl Block {
None
}
StmtKind::Set(variable_reference, expression) => {
// Update typing from reference
variable_reference.resolve_ref(&typerefs)?;
if let Some(var) = state
.ok(
variable_reference
@ -259,8 +262,11 @@ impl Block {
)
.flatten()
{
let field_ty = variable_reference.retrieve_type(&state.scope)?;
dbg!(&field_ty);
// Typecheck expression and coerce to variable type
let res = expression.typecheck(&mut state, &hints, Some(&var.ty));
let res = expression.typecheck(&mut state, &typerefs, Some(&field_ty));
// If expression resolution itself was erronous, resolve as
// Unknown.
@ -269,15 +275,11 @@ impl Block {
// Make sure the expression and variable type to really
// be the same
let res_t = state.or_else(
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
TypeKind::Vague(Vague::Unknown),
state.ok(
expr_ty.collapse_into(&field_ty),
variable_reference.meta + expression.1,
);
// Update typing to be more accurate
variable_reference.update_type(&res_t);
if !var.mutable {
state.ok::<_, Infallible>(
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
@ -296,7 +298,7 @@ impl Block {
}
StmtKind::Import(_) => todo!(), // TODO
StmtKind::Expression(expression) => {
let res = expression.typecheck(&mut state, &hints, None);
let res = expression.typecheck(&mut state, &typerefs, None);
state.or_else(res, TypeKind::Void, expression.1);
if let Ok((kind, _)) = expression.return_type() {
Some((kind, expression))
@ -316,7 +318,7 @@ impl Block {
// block)
if let Some((ReturnKind::Hard, expr)) = early_return {
let hint = state.scope.return_type_hint.clone();
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
let res = expr.typecheck(&mut state, &typerefs, hint.as_ref());
return Ok((
ReturnKind::Hard,
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
@ -329,7 +331,7 @@ impl Block {
ReturnKind::Hard => state.scope.return_type_hint.clone(),
ReturnKind::Soft => hint_t.cloned(),
};
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.as_ref());
Ok((
*return_kind,
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
@ -361,11 +363,11 @@ impl Expression {
TypeKind::Vague(Vague::Unknown),
var_ref.2,
)
.resolve_hinted(hints);
.resolve_ref(hints);
// Update typing to be more accurate
var_ref.0 = state.or_else(
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
var_ref.0.resolve_ref(hints).collapse_into(&existing),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
);
@ -437,12 +439,12 @@ impl Expression {
// return type
let ret_t = f
.ret
.collapse_into(&function_call.return_type.resolve_hinted(hints))?;
.collapse_into(&function_call.return_type.resolve_ref(hints))?;
// Update typing to be more accurate
function_call.return_type = ret_t.clone();
Ok(ret_t.resolve_hinted(hints))
Ok(ret_t.resolve_ref(hints))
} else {
Ok(function_call.return_type.clone().resolve_hinted(hints))
Ok(function_call.return_type.clone().resolve_ref(hints))
}
}
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
@ -515,7 +517,7 @@ impl Expression {
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
}
let ty = state.or_else(
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
elem_ty.resolve_ref(hints).collapse_into(&inferred_ty),
TypeKind::Vague(Vague::Unknown),
self.1,
);
@ -564,7 +566,7 @@ impl Expression {
}
ExprKind::StructIndex(expression, type_kind, field_name) => {
// Resolve expected type
let expected_ty = type_kind.resolve_hinted(hints);
let expected_ty = type_kind.resolve_ref(hints);
// Typecheck expression
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
@ -572,7 +574,10 @@ impl Expression {
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
if let TypeKind::CustomType(struct_name) = expr_ty {
let struct_type = state.scope.get_struct_type(&struct_name)?;
let struct_type = state
.scope
.get_struct_type(&struct_name)
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?;
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
// Make sure they are the same
let true_ty = state.or_else(
@ -591,7 +596,11 @@ impl Expression {
}
}
ExprKind::Struct(struct_name, items) => {
let struct_def = state.scope.get_struct_type(struct_name)?.clone();
let struct_def = state
.scope
.get_struct_type(struct_name)
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
.clone();
for (field_name, field_expr) in items {
// Get expected type, or error if field does not exist
let expected_ty = state.or_else(
@ -649,8 +658,10 @@ impl IndexedVariableReference {
if let Some(kind) = types.get(type_name) {
match &kind {
TypeDefinitionKind::Struct(struct_type) => {
if let Some((_, field_ty)) =
struct_type.0.iter().find(|(n, _)| n == field_name)
if let Some(StructField(_, field_ty, _)) = struct_type
.0
.iter()
.find(|StructField(n, _, _)| n == field_name)
{
Ok(Some(ScopeVariable {
ty: field_ty.clone(),
@ -716,37 +727,7 @@ impl Literal {
}
}
impl TypeKind {
/// Assert that a type is already known and not vague. Return said type or
/// error.
pub fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
self.known().map_err(ErrorKind::TypeIsVague)
}
/// Try to collapse a type on itself producing a default type if one exists,
/// Error if not.
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
match self {
TypeKind::Vague(vague_type) => match &vague_type {
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
Vague::Number => Ok(TypeKind::I32),
Vague::TypeRef(_) => panic!("Hinted default!"),
},
_ => Ok(self.clone()),
}
}
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
let resolved = match self {
TypeKind::Vague(Vague::TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
_ => self.clone(),
};
match resolved {
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_hinted(hints)), len),
_ => resolved,
}
}
}
impl TypeKind {}
pub trait Collapsable: Sized + Clone {
/// Try to narrow two types into one singular type. E.g. Vague(Number) and
@ -801,15 +782,3 @@ impl Collapsable for ScopeFunction {
})
}
}
impl pass::Scope {
pub fn get_struct_type(&self, name: &String) -> Result<&StructType, ErrorKind> {
let ty = self
.types
.get(&name)
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
match ty {
TypeDefinitionKind::Struct(struct_ty) => Ok(struct_ty),
}
}
}

View File

@ -13,9 +13,8 @@ use super::{
typecheck::ErrorKind,
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
types::{pick_return, ReturnType},
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression,
IndexedVariableReference, IndexedVariableReferenceKind, Module, NamedVariableRef, ReturnKind,
StmtKind, TypeDefinitionKind,
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
ReturnKind, StmtKind,
TypeKind::*,
VagueType::*,
};
@ -106,13 +105,8 @@ impl Block {
}
}
StmtKind::Set(var, expr) => {
// Get the TypeRef for this variable declaration
let var_ref = var.find_hint(&state, &inner_hints)?;
// If ok, update the MIR type to this TypeRef
if let Some((_, var_ref)) = &var_ref {
var.update_type(&var_ref.as_type());
}
// Update this MIR type to its TypeRef
let var_ref = var.into_typeref(&inner_hints);
// Infer hints for the expression itself
let inferred = expr.infer_types(&mut state, &inner_hints);
@ -153,61 +147,6 @@ impl Block {
}
}
impl IndexedVariableReference {
fn find_hint<'s>(
&self,
state: &PassState<ErrorKind>,
hints: &'s ScopeTypeRefs,
) -> Result<Option<(bool, TypeRef<'s>)>, ErrorKind> {
match &self.kind {
IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
Ok(hints.find_var(&name))
}
IndexedVariableReferenceKind::ArrayIndex(inner, _) => {
if let Some((mutable, inner_ref)) = inner.find_hint(state, hints)? {
// Check that the resolved type is at least an array, no
// need for further resolution.
let inner_ty = inner_ref.resolve_weak().unwrap();
match inner_ty {
Array(type_kind, _) => Ok(hints
.from_type(&type_kind)
.clone()
.map(|t_ref| (mutable, t_ref))),
_ => Err(ErrorKind::TriedIndexingNonArray(inner_ty.clone())),
}
} else {
Ok(None)
}
}
IndexedVariableReferenceKind::StructIndex(inner, field_name) => {
if let Some((mutable, inner_ref)) = inner.find_hint(state, hints)? {
// Check that the resolved type is at least an array, no
// need for further resolution.
let inner_ty = inner_ref.resolve_weak().unwrap();
match &inner_ty {
CustomType(struct_name) => match state.scope.types.get(&struct_name) {
Some(kind) => match kind {
TypeDefinitionKind::Struct(struct_ty) => Ok(hints
.from_type(
&struct_ty
.get_field_ty(field_name)
.cloned()
.ok_or(ErrorKind::NoSuchField(self.get_name()))?,
)
.map(|v| (mutable, v))),
},
None => Err(ErrorKind::TriedAccessingNonStruct(inner_ty.clone())),
},
_ => Err(ErrorKind::TriedAccessingNonStruct(inner_ty)),
}
} else {
Ok(None)
}
}
}
}
}
impl Expression {
fn infer_types<'s>(
&mut self,
@ -371,7 +310,10 @@ impl Expression {
let kind = expr_ty.resolve_weak().unwrap();
match kind {
CustomType(name) => {
let struct_ty = state.scope.get_struct_type(&name)?;
let struct_ty = state
.scope
.get_struct_type(&name)
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
match struct_ty.get_field_ty(&field_name) {
Some(field_ty) => {
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
@ -386,7 +328,11 @@ impl Expression {
}
}
ExprKind::Struct(struct_name, fields) => {
let expected_struct_ty = state.scope.get_struct_type(&struct_name)?.clone();
let expected_struct_ty = state
.scope
.get_struct_type(&struct_name)
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
.clone();
for field in fields {
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
let field_ty = field.1.infer_types(state, type_refs);

View File

@ -1,4 +1,8 @@
use super::*;
use super::{
typecheck::ErrorKind,
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
VagueType as Vague, *,
};
#[derive(Debug, Clone)]
pub enum ReturnTypeOther {
@ -29,11 +33,17 @@ impl TypeKind {
impl StructType {
pub fn get_field_ty(&self, name: &String) -> Option<&TypeKind> {
self.0.iter().find(|(n, _)| n == name).map(|(_, ty)| ty)
self.0
.iter()
.find(|StructField(n, _, _)| n == name)
.map(|StructField(_, ty, _)| ty)
}
pub fn get_field_ty_mut(&mut self, name: &String) -> Option<&mut TypeKind> {
self.0.iter_mut().find(|(n, _)| n == name).map(|(_, ty)| ty)
self.0
.iter_mut()
.find(|StructField(n, _, _)| n == name)
.map(|StructField(_, ty, _)| ty)
}
}
@ -173,6 +183,38 @@ pub fn pick_return<T>(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind
}
}
impl TypeKind {
/// Assert that a type is already known and not vague. Return said type or
/// error.
pub fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
self.known().map_err(ErrorKind::TypeIsVague)
}
/// Try to collapse a type on itself producing a default type if one exists,
/// Error if not.
pub fn or_default(&self) -> Result<TypeKind, ErrorKind> {
match self {
TypeKind::Vague(vague_type) => match &vague_type {
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
Vague::Number => Ok(TypeKind::I32),
Vague::TypeRef(_) => panic!("Hinted default!"),
},
_ => Ok(self.clone()),
}
}
pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
let resolved = match self {
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
_ => self.clone(),
};
match resolved {
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
_ => resolved,
}
}
}
impl IndexedVariableReference {
pub fn get_name(&self) -> String {
match &self.kind {
@ -186,13 +228,55 @@ impl IndexedVariableReference {
}
}
pub fn update_type(&mut self, new_ty: &TypeKind) {
/// Retrieve the indexed type that this variable reference is pointing to
pub fn retrieve_type(&self, scope: &pass::Scope) -> Result<TypeKind, ErrorKind> {
match &self.kind {
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => Ok(ty.clone()),
IndexedVariableReferenceKind::ArrayIndex(inner, _) => {
let inner_ty = inner.retrieve_type(scope)?;
match inner_ty {
TypeKind::Array(type_kind, _) => Ok(*type_kind),
_ => Err(ErrorKind::TriedIndexingNonArray(inner_ty)),
}
}
IndexedVariableReferenceKind::StructIndex(inner, field_name) => {
let inner_ty = inner.retrieve_type(scope)?;
match inner_ty {
TypeKind::CustomType(struct_name) => {
let struct_ty = scope
.get_struct_type(&struct_name)
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?;
struct_ty
.get_field_ty(&field_name)
.ok_or(ErrorKind::NoSuchField(field_name.clone()))
.cloned()
}
_ => Err(ErrorKind::TriedAccessingNonStruct(inner_ty)),
}
}
}
}
pub fn into_typeref<'s>(&mut self, typerefs: &'s ScopeTypeRefs) -> Option<(bool, TypeRef<'s>)> {
match &mut self.kind {
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, name, _)) => {
let t = typerefs.find_var(name)?;
*ty = t.1.as_type();
Some(t)
}
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.into_typeref(typerefs),
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.into_typeref(typerefs),
}
}
pub fn resolve_ref<'s>(&mut self, typerefs: &'s TypeRefs) -> Result<TypeKind, ErrorKind> {
match &mut self.kind {
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => {
*ty = new_ty.clone();
*ty = ty.resolve_ref(typerefs);
Ok(ty.clone())
}
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.update_type(new_ty),
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.update_type(new_ty),
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.resolve_ref(typerefs),
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.resolve_ref(typerefs),
}
}
}

View File

@ -0,0 +1,17 @@
// Arithmetic, function calls and imports!
struct Test {
field: i32,
second: [u32; 4]
}
fn main() -> u32 {
let mut value = [Test {
field: 5,
second: [6, 3, 17, 8],
}];
value[0].second[2] = 99;
return value[0].second[2];
}

View File

@ -6,10 +6,12 @@ struct Test {
}
fn main() -> u32 {
let value = Test {
let mut value = Test {
field: 5,
second: 3,
};
value.second = 17;
return value.second;
}