Compare commits
4 Commits
master
...
enhance/gl
Author | SHA1 | Date |
---|---|---|
David Mak | 3afe69fcda | |
David Mak | b538611cb0 | |
David Mak | fa573390b1 | |
David Mak | 3ca70e679a |
|
@ -2886,7 +2886,31 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||||
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
||||||
None => {
|
None => {
|
||||||
let resolver = ctx.resolver.clone();
|
let resolver = ctx.resolver.clone();
|
||||||
resolver.get_symbol_value(*id, ctx, generator).unwrap()
|
let value = resolver.get_symbol_value(*id, ctx, generator).unwrap();
|
||||||
|
|
||||||
|
let globals = ctx
|
||||||
|
.top_level
|
||||||
|
.definitions
|
||||||
|
.read()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|def| {
|
||||||
|
if let TopLevelDef::Variable { simple_name, ty, .. } = &*def.read() {
|
||||||
|
Some((*simple_name, *ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
if let Some((_, ty)) = globals.iter().find(|(name, _)| name == id) {
|
||||||
|
let ptr = value
|
||||||
|
.to_basic_value_enum(ctx, generator, *ty)
|
||||||
|
.map(BasicValueEnum::into_pointer_value)?;
|
||||||
|
|
||||||
|
ctx.builder.build_load(ptr, id.to_string().as_str()).map(Into::into).unwrap()
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExprKind::List { elts, .. } => {
|
ExprKind::List { elts, .. } => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use nac3parser::ast::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
type_inferencer::{IdentifierInfo, Inferencer},
|
type_inferencer::{DeclarationSource, IdentifierInfo, Inferencer},
|
||||||
typedef::{Type, TypeEnum},
|
typedef::{Type, TypeEnum},
|
||||||
};
|
};
|
||||||
use crate::toplevel::helper::PrimDef;
|
use crate::toplevel::helper::PrimDef;
|
||||||
|
@ -34,6 +34,20 @@ impl<'a> Inferencer<'a> {
|
||||||
Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)]))
|
Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)]))
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
|
// If `id` refers to a declared symbol, reject this assignment if it is used in the
|
||||||
|
// context of an (implicit) global variable
|
||||||
|
if let Some(id_info) = self.defined_identifiers.get(id) {
|
||||||
|
if matches!(
|
||||||
|
id_info.source,
|
||||||
|
DeclarationSource::Global { is_explicit: Some(false) }
|
||||||
|
) {
|
||||||
|
return Err(HashSet::from([format!(
|
||||||
|
"cannot access local variable '{id}' before it is declared (at {})",
|
||||||
|
pattern.location
|
||||||
|
)]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !defined_identifiers.contains_key(id) {
|
if !defined_identifiers.contains_key(id) {
|
||||||
defined_identifiers.insert(*id, IdentifierInfo::default());
|
defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
|
@ -104,7 +118,7 @@ impl<'a> Inferencer<'a> {
|
||||||
*id,
|
*id,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.defined_identifiers.insert(*id, IdentifierInfo::default());
|
defined_identifiers.insert(*id, IdentifierInfo::default());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
|
@ -368,9 +382,9 @@ impl<'a> Inferencer<'a> {
|
||||||
StmtKind::Global { names, .. } => {
|
StmtKind::Global { names, .. } => {
|
||||||
for id in names {
|
for id in names {
|
||||||
if let Some(id_info) = defined_identifiers.get(id) {
|
if let Some(id_info) = defined_identifiers.get(id) {
|
||||||
if !id_info.is_global {
|
if id_info.source == DeclarationSource::Local {
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
"name '{id}' is assigned to before global declaration at {}",
|
"name '{id}' is used prior to global declaration at {}",
|
||||||
stmt.location,
|
stmt.location,
|
||||||
)]));
|
)]));
|
||||||
}
|
}
|
||||||
|
@ -385,8 +399,12 @@ impl<'a> Inferencer<'a> {
|
||||||
*id,
|
*id,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.defined_identifiers
|
self.defined_identifiers.insert(
|
||||||
.insert(*id, IdentifierInfo { is_global: true });
|
*id,
|
||||||
|
IdentifierInfo {
|
||||||
|
source: DeclarationSource::Global { is_explicit: Some(true) },
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(HashSet::from([format!(
|
return Err(HashSet::from([format!(
|
||||||
|
|
|
@ -88,11 +88,31 @@ impl PrimitiveStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The location where an identifier declaration refers to.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum DeclarationSource {
|
||||||
|
/// Local scope.
|
||||||
|
Local,
|
||||||
|
|
||||||
|
/// Global scope.
|
||||||
|
Global {
|
||||||
|
/// Whether the identifier is declared by the use of `global` statement. This field is
|
||||||
|
/// [`None`] if the identifier does not refer to a variable.
|
||||||
|
is_explicit: Option<bool>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/// Information regarding a defined identifier.
|
/// Information regarding a defined identifier.
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct IdentifierInfo {
|
pub struct IdentifierInfo {
|
||||||
/// Whether this identifier refers to a global variable.
|
/// Whether this identifier refers to a global variable.
|
||||||
pub is_global: bool,
|
pub source: DeclarationSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IdentifierInfo {
|
||||||
|
fn default() -> Self {
|
||||||
|
IdentifierInfo { source: DeclarationSource::Local }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentifierInfo {
|
impl IdentifierInfo {
|
||||||
|
@ -566,15 +586,45 @@ impl<'a> Fold<()> for Inferencer<'a> {
|
||||||
unreachable!("must be tobj")
|
unreachable!("must be tobj")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let top_level_defs = &self.top_level.definitions.read();
|
||||||
|
|
||||||
if !self.defined_identifiers.contains_key(id) {
|
if !self.defined_identifiers.contains_key(id) {
|
||||||
match self.function_data.resolver.get_symbol_type(
|
match self.function_data.resolver.get_symbol_type(
|
||||||
self.unifier,
|
self.unifier,
|
||||||
&self.top_level.definitions.read(),
|
top_level_defs,
|
||||||
self.primitives,
|
self.primitives,
|
||||||
*id,
|
*id,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.defined_identifiers.insert(*id, IdentifierInfo::default());
|
// Determine if the referenced id refers to a global symbol
|
||||||
|
let is_explicit = top_level_defs
|
||||||
|
.iter()
|
||||||
|
.map(|def| match *def.read() {
|
||||||
|
TopLevelDef::Class { name, .. } => (name, false),
|
||||||
|
TopLevelDef::Function { simple_name, .. } => {
|
||||||
|
(simple_name, false)
|
||||||
|
}
|
||||||
|
TopLevelDef::Variable { simple_name, .. } => {
|
||||||
|
(simple_name, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.find(|(global, _)| global == id)
|
||||||
|
.map(|(_, has_explicit_prop)| has_explicit_prop);
|
||||||
|
|
||||||
|
self.defined_identifiers.insert(
|
||||||
|
*id,
|
||||||
|
IdentifierInfo {
|
||||||
|
source: match is_explicit {
|
||||||
|
Some(true) => DeclarationSource::Global {
|
||||||
|
is_explicit: Some(false),
|
||||||
|
},
|
||||||
|
Some(false) => {
|
||||||
|
DeclarationSource::Global { is_explicit: None }
|
||||||
|
}
|
||||||
|
None => DeclarationSource::Local,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return report_error(
|
return report_error(
|
||||||
|
|
Loading…
Reference in New Issue