Compare commits
No commits in common. "4ad871ff3d1d3a6e4f57a246637dbf2e95a6a076" and "233ddb60f7f31c67ae1399e8eaf68ac549e8e2c4" have entirely different histories.
4ad871ff3d
...
233ddb60f7
@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
BINARY="$(echo $1 | cut -d'.' -f1)"".out"
|
BINARY="$(echo $1 | cut -d'.' -f1)"".out"
|
||||||
|
|
||||||
echo $1
|
|
||||||
|
|
||||||
make clean SRC=$1 ; make SRC=$1 && echo ""
|
make clean SRC=$1 ; make SRC=$1 && echo ""
|
||||||
|
|
||||||
$BINARY ; echo "Return value: ""$?"
|
$BINARY ; echo "Return value: ""$?"
|
||||||
|
@ -310,12 +310,10 @@ impl Builder {
|
|||||||
Instr::ArrayAlloca(_, _) => Ok(()),
|
Instr::ArrayAlloca(_, _) => Ok(()),
|
||||||
Instr::GetElemPtr(ptr_val, _) => {
|
Instr::GetElemPtr(ptr_val, _) => {
|
||||||
let ptr_ty = ptr_val.get_type(&self)?;
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
match ptr_ty {
|
if let Type::Ptr(_) = ptr_ty {
|
||||||
Type::CustomType(custom) => match self.type_data(&custom).kind {
|
Ok(())
|
||||||
CustomTypeKind::NamedStruct(_) => Ok(()),
|
} else {
|
||||||
},
|
Err(()) // TODO error: not a pointer
|
||||||
Type::Ptr(_) => Ok(()),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::GetStructElemPtr(ptr_val, idx) => {
|
Instr::GetStructElemPtr(ptr_val, idx) => {
|
||||||
|
@ -21,7 +21,7 @@ use llvm_sys::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CustomTypeKind,
|
CustomTypeKind, NamedStruct,
|
||||||
builder::{TypeHolder, TypeValue},
|
builder::{TypeHolder, TypeValue},
|
||||||
util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring},
|
util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring},
|
||||||
};
|
};
|
||||||
@ -496,11 +496,20 @@ impl InstructionHolder {
|
|||||||
module.values.get(arr).unwrap().value_ref,
|
module.values.get(arr).unwrap().value_ref,
|
||||||
llvm_indices.as_mut_ptr(),
|
llvm_indices.as_mut_ptr(),
|
||||||
llvm_indices.len() as u32,
|
llvm_indices.len() as u32,
|
||||||
into_cstring(format!("array_gep")).as_ptr(),
|
into_cstring(format!(
|
||||||
|
"array_gep_{:?}",
|
||||||
|
indices
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("_")
|
||||||
|
))
|
||||||
|
.as_ptr(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
GetStructElemPtr(struct_val, idx) => {
|
GetStructElemPtr(struct_val, idx) => {
|
||||||
let t = struct_val.get_type(module.builder).unwrap();
|
let t = struct_val.get_type(module.builder).unwrap();
|
||||||
|
dbg!(&t);
|
||||||
let Type::Ptr(struct_t) = t else { panic!() };
|
let Type::Ptr(struct_t) = t else { panic!() };
|
||||||
|
|
||||||
let type_fmt = if let Type::CustomType(type_val) = *struct_t {
|
let type_fmt = if let Type::CustomType(type_val) = *struct_t {
|
||||||
@ -508,6 +517,7 @@ impl InstructionHolder {
|
|||||||
} else {
|
} else {
|
||||||
format!("{:?}", struct_t)
|
format!("{:?}", struct_t)
|
||||||
};
|
};
|
||||||
|
dbg!(idx);
|
||||||
|
|
||||||
LLVMBuildStructGEP2(
|
LLVMBuildStructGEP2(
|
||||||
module.builder_ref,
|
module.builder_ref,
|
||||||
|
@ -425,22 +425,12 @@ impl Parse for VariableReference {
|
|||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
while let Ok(val) = stream.parse::<ValueIndex>() {
|
while let Ok(ArrayValueIndex(idx)) = stream.parse() {
|
||||||
match val {
|
|
||||||
ValueIndex::Array(ArrayValueIndex(idx)) => {
|
|
||||||
var_ref = VariableReference(
|
var_ref = VariableReference(
|
||||||
VariableReferenceKind::ArrayIndex(Box::new(var_ref), idx),
|
VariableReferenceKind::ArrayIndex(Box::new(var_ref), idx),
|
||||||
stream.get_range().unwrap(),
|
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)
|
Ok(var_ref)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,7 +2,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self},
|
ast::{self},
|
||||||
mir::{self, NamedVariableRef, StmtKind, StructField, StructType},
|
mir::{self, NamedVariableRef, StmtKind, StructType},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl mir::Context {
|
impl mir::Context {
|
||||||
@ -71,13 +71,7 @@ impl ast::Module {
|
|||||||
mir::TypeDefinitionKind::Struct(StructType(
|
mir::TypeDefinitionKind::Struct(StructType(
|
||||||
struct_definition_fields
|
struct_definition_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| (s.name.clone(), s.ty.clone().into()))
|
||||||
StructField(
|
|
||||||
s.name.clone(),
|
|
||||||
s.ty.clone().into(),
|
|
||||||
s.range.into(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use reid_lib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{
|
use crate::mir::{
|
||||||
self, types::ReturnType, IndexedVariableReference, NamedVariableRef, StructField, StructType,
|
self, types::ReturnType, IndexedVariableReference, NamedVariableRef, StructType,
|
||||||
TypeDefinitionKind, TypeKind,
|
TypeDefinitionKind, TypeKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ impl mir::Module {
|
|||||||
// TODO: Reorder custom-type definitions such that
|
// TODO: Reorder custom-type definitions such that
|
||||||
// inner types get evaluated first. Otherwise this
|
// inner types get evaluated first. Otherwise this
|
||||||
// will cause a panic!
|
// will cause a panic!
|
||||||
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
|
.map(|(_, t)| t.get_type(&type_values))
|
||||||
.collect(),
|
.collect(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
@ -80,14 +80,14 @@ impl mir::Module {
|
|||||||
let param_types: Vec<Type> = function
|
let param_types: Vec<Type> = function
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, p)| p.get_type(&type_values, &types))
|
.map(|(_, p)| p.get_type(&type_values))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_main = self.is_main && function.name == "main";
|
let is_main = self.is_main && function.name == "main";
|
||||||
let func = match &function.kind {
|
let func = match &function.kind {
|
||||||
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
||||||
&function.name,
|
&function.name,
|
||||||
function.return_type.get_type(&type_values, &types),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_pub: function.is_pub || is_main,
|
is_pub: function.is_pub || is_main,
|
||||||
@ -98,7 +98,7 @@ impl mir::Module {
|
|||||||
),
|
),
|
||||||
mir::FunctionDefinitionKind::Extern(imported) => module.function(
|
mir::FunctionDefinitionKind::Extern(imported) => module.function(
|
||||||
&function.name,
|
&function.name,
|
||||||
function.return_type.get_type(&type_values, &types),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_extern: true,
|
is_extern: true,
|
||||||
@ -120,7 +120,7 @@ impl mir::Module {
|
|||||||
p_name.clone(),
|
p_name.clone(),
|
||||||
StackValue(
|
StackValue(
|
||||||
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
||||||
p_ty.get_type(&type_values, &types),
|
p_ty.get_type(&type_values),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -175,22 +175,6 @@ pub enum StackValueKind {
|
|||||||
Mutable(InstructionValue),
|
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> {
|
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||||
fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
|
fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
|
||||||
Scope {
|
Scope {
|
||||||
@ -218,6 +202,48 @@ 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 {
|
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 {
|
||||||
@ -229,22 +255,13 @@ impl mir::Statement {
|
|||||||
match mutable {
|
match mutable {
|
||||||
false => StackValueKind::Immutable(value),
|
false => StackValueKind::Immutable(value),
|
||||||
true => match ty {
|
true => match ty {
|
||||||
// Struct is already allocated at initialization
|
|
||||||
TypeKind::Array(_, _) => StackValueKind::Mutable(value),
|
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({
|
_ => StackValueKind::Mutable({
|
||||||
let alloca = scope
|
let alloca = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Alloca(
|
.build(Instr::Alloca(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
ty.get_type(scope.type_values, scope.types),
|
ty.get_type(scope.type_values),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scope.block.build(Instr::Store(alloca, value)).unwrap();
|
scope.block.build(Instr::Store(alloca, value)).unwrap();
|
||||||
@ -252,18 +269,30 @@ impl mir::Statement {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ty.get_type(scope.type_values, scope.types),
|
ty.get_type(scope.type_values),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
mir::StmtKind::Set(var, val) => {
|
mir::StmtKind::Set(var, val) => {
|
||||||
if let Some(StackValue(kind, _)) = var.get_stack_value(scope, false) {
|
if let Some((StackValue(kind, mut ty), indices)) = var.get_stack_value(scope) {
|
||||||
match kind {
|
match kind {
|
||||||
StackValueKind::Immutable(_) => {
|
StackValueKind::Immutable(_) => {
|
||||||
panic!("Tried to mutate an immutable variable")
|
panic!("Tried to mutate an immutable variable")
|
||||||
}
|
}
|
||||||
StackValueKind::Mutable(ptr) => {
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
let expression = val.codegen(scope).unwrap();
|
let expression = val.codegen(scope).unwrap();
|
||||||
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
|
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
|
||||||
}
|
}
|
||||||
@ -425,10 +454,7 @@ impl mir::Expression {
|
|||||||
Some(
|
Some(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Load(
|
.build(Instr::Load(ptr, val_t.get_type(scope.type_values)))
|
||||||
ptr,
|
|
||||||
val_t.get_type(scope.type_values, scope.types),
|
|
||||||
))
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -446,7 +472,7 @@ impl mir::Expression {
|
|||||||
let array = scope
|
let array = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::ArrayAlloca(
|
.build(Instr::ArrayAlloca(
|
||||||
instr_t.get_type(scope.type_values, scope.types),
|
instr_t.get_type(scope.type_values),
|
||||||
instr_list.len() as u32,
|
instr_list.len() as u32,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -476,14 +502,10 @@ impl mir::Expression {
|
|||||||
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
|
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
dbg!(&type_kind.get_type(scope.type_values, scope.types));
|
|
||||||
Some(
|
Some(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Load(
|
.build(Instr::Load(ptr, type_kind.get_type(scope.type_values)))
|
||||||
ptr,
|
|
||||||
type_kind.get_type(scope.type_values, scope.types),
|
|
||||||
))
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -512,85 +534,6 @@ 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 {
|
impl mir::CmpOperator {
|
||||||
fn int_predicate(&self) -> CmpPredicate {
|
fn int_predicate(&self) -> CmpPredicate {
|
||||||
match self {
|
match self {
|
||||||
@ -653,11 +596,7 @@ impl mir::Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
fn get_type(
|
fn get_type(&self, type_vals: &HashMap<String, TypeValue>) -> Type {
|
||||||
&self,
|
|
||||||
type_vals: &HashMap<String, TypeValue>,
|
|
||||||
typedefs: &HashMap<TypeValue, TypeDefinitionKind>,
|
|
||||||
) -> Type {
|
|
||||||
match &self {
|
match &self {
|
||||||
TypeKind::I8 => Type::I8,
|
TypeKind::I8 => Type::I8,
|
||||||
TypeKind::I16 => Type::I16,
|
TypeKind::I16 => Type::I16,
|
||||||
@ -671,16 +610,10 @@ impl TypeKind {
|
|||||||
TypeKind::U128 => Type::U128,
|
TypeKind::U128 => Type::U128,
|
||||||
TypeKind::Bool => Type::Bool,
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
|
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
|
||||||
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals, typedefs))),
|
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals))),
|
||||||
TypeKind::Void => Type::Void,
|
TypeKind::Void => Type::Void,
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
TypeKind::CustomType(n) => {
|
TypeKind::CustomType(n) => Type::CustomType(type_vals.get(n).unwrap().clone()),
|
||||||
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)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ impl Display for TypeDefinitionKind {
|
|||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
let mut state = Default::default();
|
let mut state = Default::default();
|
||||||
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
||||||
for field in &items.0 {
|
for (field_name, field_ty) in &items.0 {
|
||||||
writeln!(inner_f, "{},", field)?;
|
writeln!(inner_f, "{}: {:?},", field_name, field_ty)?;
|
||||||
}
|
}
|
||||||
f.write_char('}')
|
f.write_char('}')
|
||||||
}
|
}
|
||||||
@ -64,12 +64,6 @@ 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 {
|
impl Display for FunctionDefinition {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
@ -82,21 +82,20 @@ pub enum VagueType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StructType(pub Vec<StructField>);
|
pub struct StructType(pub Vec<(String, TypeKind)>);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct StructField(pub String, pub TypeKind, pub Metadata);
|
|
||||||
|
|
||||||
impl StructType {
|
impl StructType {
|
||||||
pub fn find_index(&self, name: &String) -> Option<u32> {
|
pub fn find_index(&self, name: &String) -> Option<u32> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, StructField(n, _, _))| n == name)
|
.find(|(_, (n, _))| n == name)
|
||||||
.map(|(i, _)| i as u32)
|
.map(|(i, _)| i as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type TypedefMap = HashMap<String, TypeDefinitionKind>;
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
||||||
if let TypeKind::Vague(vague) = self {
|
if let TypeKind::Vague(vague) = self {
|
||||||
@ -107,6 +106,55 @@ 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I8(i8),
|
I8(i8),
|
||||||
|
@ -33,6 +33,9 @@ impl<TErr: STDError> STDError for Error<TErr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<TErr: STDError> {
|
pub struct State<TErr: STDError> {
|
||||||
pub errors: Vec<Error<TErr>>,
|
pub errors: Vec<Error<TErr>>,
|
||||||
@ -81,9 +84,6 @@ 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> {
|
impl<T: std::fmt::Debug> Default for Storage<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(Default::default())
|
Self(Default::default())
|
||||||
@ -114,24 +114,6 @@ pub struct Scope {
|
|||||||
pub return_type_hint: Option<TypeKind>,
|
pub return_type_hint: Option<TypeKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
|
||||||
pub fn inner(&self) -> Scope {
|
|
||||||
Scope {
|
|
||||||
function_returns: self.function_returns.clone(),
|
|
||||||
variables: self.variables.clone(),
|
|
||||||
types: self.types.clone(),
|
|
||||||
return_type_hint: self.return_type_hint.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ScopeFunction {
|
pub struct ScopeFunction {
|
||||||
pub ret: TypeKind,
|
pub ret: TypeKind,
|
||||||
@ -144,6 +126,21 @@ pub struct ScopeVariable {
|
|||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn inner(&self) -> Scope {
|
||||||
|
Scope {
|
||||||
|
function_returns: self.function_returns.clone(),
|
||||||
|
variables: self.variables.clone(),
|
||||||
|
types: self.types.clone(),
|
||||||
|
return_type_hint: self.return_type_hint.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_typedefs(&self) -> &TypedefMap {
|
||||||
|
&self.types.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
||||||
state: &'st mut State<TError>,
|
state: &'st mut State<TError>,
|
||||||
pub scope: &'sc mut Scope,
|
pub scope: &'sc mut Scope,
|
||||||
|
@ -71,7 +71,7 @@ fn check_typedefs_for_recursion<'a, 'b>(
|
|||||||
) {
|
) {
|
||||||
match &typedef.kind {
|
match &typedef.kind {
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||||
for field_ty in fields.iter().map(|StructField(_, ty, _)| ty) {
|
for field_ty in fields.iter().map(|(_, ty)| ty) {
|
||||||
if let TypeKind::CustomType(name) = field_ty {
|
if let TypeKind::CustomType(name) = field_ty {
|
||||||
if seen.contains(name) {
|
if seen.contains(name) {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
@ -103,11 +103,11 @@ impl<'t> Pass for TypeCheck<'t> {
|
|||||||
match kind {
|
match kind {
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||||
let mut fieldmap = HashMap::new();
|
let mut fieldmap = HashMap::new();
|
||||||
for StructField(name, field_ty, field_meta) in fields {
|
for (name, field_ty) in fields {
|
||||||
if let Some(_) = fieldmap.insert(name, field_ty) {
|
if let Some(_) = fieldmap.insert(name, field_ty) {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::DuplicateStructField(name.clone())),
|
Err(ErrorKind::DuplicateStructField(name.clone())),
|
||||||
field_meta.clone(),
|
meta.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ impl Block {
|
|||||||
fn typecheck(
|
fn typecheck(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut PassState<ErrorKind>,
|
||||||
typerefs: &TypeRefs,
|
hints: &TypeRefs,
|
||||||
hint_t: Option<&TypeKind>,
|
hint_t: Option<&TypeKind>,
|
||||||
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut state = state.inner();
|
||||||
@ -197,10 +197,10 @@ impl Block {
|
|||||||
let ret = match &mut statement.0 {
|
let ret = match &mut statement.0 {
|
||||||
StmtKind::Let(variable_reference, mutable, expression) => {
|
StmtKind::Let(variable_reference, mutable, expression) => {
|
||||||
// Resolve possible hint in var reference
|
// Resolve possible hint in var reference
|
||||||
let var_t_resolved = variable_reference.0.resolve_ref(&typerefs);
|
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, &typerefs, 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.
|
||||||
@ -222,7 +222,7 @@ impl Block {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Re-typecheck and coerce expression to default type
|
// Re-typecheck and coerce expression to default type
|
||||||
let expr_res = expression.typecheck(&mut state, &typerefs, 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
|
||||||
@ -251,9 +251,6 @@ impl Block {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
StmtKind::Set(variable_reference, expression) => {
|
StmtKind::Set(variable_reference, expression) => {
|
||||||
// Update typing from reference
|
|
||||||
variable_reference.resolve_ref(&typerefs)?;
|
|
||||||
|
|
||||||
if let Some(var) = state
|
if let Some(var) = state
|
||||||
.ok(
|
.ok(
|
||||||
variable_reference
|
variable_reference
|
||||||
@ -262,11 +259,8 @@ impl Block {
|
|||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
let field_ty = variable_reference.retrieve_type(&state.scope)?;
|
|
||||||
dbg!(&field_ty);
|
|
||||||
|
|
||||||
// Typecheck expression and coerce to variable type
|
// Typecheck expression and coerce to variable type
|
||||||
let res = expression.typecheck(&mut state, &typerefs, Some(&field_ty));
|
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.
|
||||||
@ -275,11 +269,15 @@ impl Block {
|
|||||||
|
|
||||||
// Make sure the expression and variable type to really
|
// Make sure the expression and variable type to really
|
||||||
// be the same
|
// be the same
|
||||||
state.ok(
|
let res_t = state.or_else(
|
||||||
expr_ty.collapse_into(&field_ty),
|
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
|
||||||
|
TypeKind::Vague(Vague::Unknown),
|
||||||
variable_reference.meta + expression.1,
|
variable_reference.meta + expression.1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Update typing to be more accurate
|
||||||
|
variable_reference.update_type(&res_t);
|
||||||
|
|
||||||
if !var.mutable {
|
if !var.mutable {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
|
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
|
||||||
@ -298,7 +296,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(), // TODO
|
StmtKind::Import(_) => todo!(), // TODO
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, &typerefs, None);
|
let res = expression.typecheck(&mut state, &hints, None);
|
||||||
state.or_else(res, TypeKind::Void, expression.1);
|
state.or_else(res, TypeKind::Void, expression.1);
|
||||||
if let Ok((kind, _)) = expression.return_type() {
|
if let Ok((kind, _)) = expression.return_type() {
|
||||||
Some((kind, expression))
|
Some((kind, expression))
|
||||||
@ -318,7 +316,7 @@ impl Block {
|
|||||||
// 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.clone();
|
let hint = state.scope.return_type_hint.clone();
|
||||||
let res = expr.typecheck(&mut state, &typerefs, hint.as_ref());
|
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
|
||||||
return Ok((
|
return Ok((
|
||||||
ReturnKind::Hard,
|
ReturnKind::Hard,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||||
@ -331,7 +329,7 @@ impl Block {
|
|||||||
ReturnKind::Hard => state.scope.return_type_hint.clone(),
|
ReturnKind::Hard => state.scope.return_type_hint.clone(),
|
||||||
ReturnKind::Soft => hint_t.cloned(),
|
ReturnKind::Soft => hint_t.cloned(),
|
||||||
};
|
};
|
||||||
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.as_ref());
|
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
|
||||||
Ok((
|
Ok((
|
||||||
*return_kind,
|
*return_kind,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||||
@ -363,11 +361,11 @@ impl Expression {
|
|||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
)
|
)
|
||||||
.resolve_ref(hints);
|
.resolve_hinted(hints);
|
||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
var_ref.0 = state.or_else(
|
var_ref.0 = state.or_else(
|
||||||
var_ref.0.resolve_ref(hints).collapse_into(&existing),
|
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
);
|
);
|
||||||
@ -439,12 +437,12 @@ impl Expression {
|
|||||||
// return type
|
// return type
|
||||||
let ret_t = f
|
let ret_t = f
|
||||||
.ret
|
.ret
|
||||||
.collapse_into(&function_call.return_type.resolve_ref(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.clone();
|
function_call.return_type = ret_t.clone();
|
||||||
Ok(ret_t.resolve_ref(hints))
|
Ok(ret_t.resolve_hinted(hints))
|
||||||
} else {
|
} else {
|
||||||
Ok(function_call.return_type.clone().resolve_ref(hints))
|
Ok(function_call.return_type.clone().resolve_hinted(hints))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
@ -517,7 +515,7 @@ impl Expression {
|
|||||||
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
|
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
|
||||||
}
|
}
|
||||||
let ty = state.or_else(
|
let ty = state.or_else(
|
||||||
elem_ty.resolve_ref(hints).collapse_into(&inferred_ty),
|
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
@ -566,7 +564,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
||||||
// Resolve expected type
|
// Resolve expected type
|
||||||
let expected_ty = type_kind.resolve_ref(hints);
|
let expected_ty = type_kind.resolve_hinted(hints);
|
||||||
|
|
||||||
// Typecheck expression
|
// Typecheck expression
|
||||||
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
|
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
|
||||||
@ -574,10 +572,7 @@ impl Expression {
|
|||||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||||
|
|
||||||
if let TypeKind::CustomType(struct_name) = expr_ty {
|
if let TypeKind::CustomType(struct_name) = expr_ty {
|
||||||
let struct_type = state
|
let struct_type = state.scope.get_struct_type(&struct_name)?;
|
||||||
.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) {
|
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
||||||
// Make sure they are the same
|
// Make sure they are the same
|
||||||
let true_ty = state.or_else(
|
let true_ty = state.or_else(
|
||||||
@ -596,11 +591,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_name, items) => {
|
ExprKind::Struct(struct_name, items) => {
|
||||||
let struct_def = state
|
let struct_def = state.scope.get_struct_type(struct_name)?.clone();
|
||||||
.scope
|
|
||||||
.get_struct_type(struct_name)
|
|
||||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
|
||||||
.clone();
|
|
||||||
for (field_name, field_expr) in items {
|
for (field_name, field_expr) in items {
|
||||||
// Get expected type, or error if field does not exist
|
// Get expected type, or error if field does not exist
|
||||||
let expected_ty = state.or_else(
|
let expected_ty = state.or_else(
|
||||||
@ -658,10 +649,8 @@ impl IndexedVariableReference {
|
|||||||
if let Some(kind) = types.get(type_name) {
|
if let Some(kind) = types.get(type_name) {
|
||||||
match &kind {
|
match &kind {
|
||||||
TypeDefinitionKind::Struct(struct_type) => {
|
TypeDefinitionKind::Struct(struct_type) => {
|
||||||
if let Some(StructField(_, field_ty, _)) = struct_type
|
if let Some((_, field_ty)) =
|
||||||
.0
|
struct_type.0.iter().find(|(n, _)| n == field_name)
|
||||||
.iter()
|
|
||||||
.find(|StructField(n, _, _)| n == field_name)
|
|
||||||
{
|
{
|
||||||
Ok(Some(ScopeVariable {
|
Ok(Some(ScopeVariable {
|
||||||
ty: field_ty.clone(),
|
ty: field_ty.clone(),
|
||||||
@ -727,7 +716,37 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {}
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Collapsable: Sized + Clone {
|
pub trait Collapsable: Sized + Clone {
|
||||||
/// Try to narrow two types into one singular type. E.g. Vague(Number) and
|
/// Try to narrow two types into one singular type. E.g. Vague(Number) and
|
||||||
@ -782,3 +801,15 @@ 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,8 +13,9 @@ use super::{
|
|||||||
typecheck::ErrorKind,
|
typecheck::ErrorKind,
|
||||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||||
types::{pick_return, ReturnType},
|
types::{pick_return, ReturnType},
|
||||||
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
|
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression,
|
||||||
ReturnKind, StmtKind,
|
IndexedVariableReference, IndexedVariableReferenceKind, Module, NamedVariableRef, ReturnKind,
|
||||||
|
StmtKind, TypeDefinitionKind,
|
||||||
TypeKind::*,
|
TypeKind::*,
|
||||||
VagueType::*,
|
VagueType::*,
|
||||||
};
|
};
|
||||||
@ -105,8 +106,13 @@ impl Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Set(var, expr) => {
|
StmtKind::Set(var, expr) => {
|
||||||
// Update this MIR type to its TypeRef
|
// Get the TypeRef for this variable declaration
|
||||||
let var_ref = var.into_typeref(&inner_hints);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
@ -147,6 +153,61 @@ 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 {
|
impl Expression {
|
||||||
fn infer_types<'s>(
|
fn infer_types<'s>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -310,10 +371,7 @@ impl Expression {
|
|||||||
let kind = expr_ty.resolve_weak().unwrap();
|
let kind = expr_ty.resolve_weak().unwrap();
|
||||||
match kind {
|
match kind {
|
||||||
CustomType(name) => {
|
CustomType(name) => {
|
||||||
let struct_ty = state
|
let struct_ty = state.scope.get_struct_type(&name)?;
|
||||||
.scope
|
|
||||||
.get_struct_type(&name)
|
|
||||||
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
|
|
||||||
match struct_ty.get_field_ty(&field_name) {
|
match struct_ty.get_field_ty(&field_name) {
|
||||||
Some(field_ty) => {
|
Some(field_ty) => {
|
||||||
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
||||||
@ -328,11 +386,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_name, fields) => {
|
ExprKind::Struct(struct_name, fields) => {
|
||||||
let expected_struct_ty = state
|
let expected_struct_ty = state.scope.get_struct_type(&struct_name)?.clone();
|
||||||
.scope
|
|
||||||
.get_struct_type(&struct_name)
|
|
||||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
|
||||||
.clone();
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||||
let field_ty = field.1.infer_types(state, type_refs);
|
let field_ty = field.1.infer_types(state, type_refs);
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
use super::{
|
use super::*;
|
||||||
typecheck::ErrorKind,
|
|
||||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
|
||||||
VagueType as Vague, *,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ReturnTypeOther {
|
pub enum ReturnTypeOther {
|
||||||
@ -33,17 +29,11 @@ impl TypeKind {
|
|||||||
|
|
||||||
impl StructType {
|
impl StructType {
|
||||||
pub fn get_field_ty(&self, name: &String) -> Option<&TypeKind> {
|
pub fn get_field_ty(&self, name: &String) -> Option<&TypeKind> {
|
||||||
self.0
|
self.0.iter().find(|(n, _)| n == name).map(|(_, ty)| ty)
|
||||||
.iter()
|
|
||||||
.find(|StructField(n, _, _)| n == name)
|
|
||||||
.map(|StructField(_, ty, _)| ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_field_ty_mut(&mut self, name: &String) -> Option<&mut TypeKind> {
|
pub fn get_field_ty_mut(&mut self, name: &String) -> Option<&mut TypeKind> {
|
||||||
self.0
|
self.0.iter_mut().find(|(n, _)| n == name).map(|(_, ty)| ty)
|
||||||
.iter_mut()
|
|
||||||
.find(|StructField(n, _, _)| n == name)
|
|
||||||
.map(|StructField(_, ty, _)| ty)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,38 +173,6 @@ 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 {
|
impl IndexedVariableReference {
|
||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
@ -228,55 +186,13 @@ impl IndexedVariableReference {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the indexed type that this variable reference is pointing to
|
pub fn update_type(&mut self, new_ty: &TypeKind) {
|
||||||
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 {
|
match &mut self.kind {
|
||||||
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => {
|
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => {
|
||||||
*ty = ty.resolve_ref(typerefs);
|
*ty = new_ty.clone();
|
||||||
Ok(ty.clone())
|
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.resolve_ref(typerefs),
|
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.update_type(new_ty),
|
||||||
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.resolve_ref(typerefs),
|
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.update_type(new_ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
// 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];
|
|
||||||
}
|
|
@ -6,12 +6,10 @@ struct Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let mut value = Test {
|
let value = Test {
|
||||||
field: 5,
|
field: 5,
|
||||||
second: 3,
|
second: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
value.second = 17;
|
|
||||||
|
|
||||||
return value.second;
|
return value.second;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user