Skip to content

Commit de71415

Browse files
gebnerCopilot
andcommitted
Add global variable support to parser and IR
- Add GlobalVar struct and DeclT::GlobalVar variant to IR - Parse VarDecl in C++ frontend with _pure attribute support - Add Option<Rc<Expr>> type to Zngur FFI for optional initializers - Register global vars in Env for type checking and name resolution - Emit _pure globals as let-definitions; non-pure globals report error - Treat global var references as rvalues (no dereference) - Add test/global_var.c with pure bool globals and assertions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a6b7578 commit de71415

11 files changed

Lines changed: 182 additions & 2 deletions

File tree

cpp/iface.zng

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type bool {
1818
use ::num_bigint::BigInt as BigInt;
1919
use ::std::rc::Rc as Rc;
2020
use ::core::result::Result as Result;
21+
use ::core::option::Option as Option;
2122
use ::std::vec::Vec as Vec;
2223
use crate::ir::Ident as Ident;
2324
use crate::ir::SourceInfo as SourceInfo;
@@ -62,6 +63,12 @@ mod crate::ir {
6263
fn push(&mut self, Rc<Expr>);
6364
}
6465

66+
type Option<Rc<Expr>> {
67+
#layout(size=8, align=8);
68+
constructor None;
69+
constructor Some(Rc<Expr>);
70+
}
71+
6572
type Rc<Stmt> {
6673
#layout(size=8, align=8);
6774
fn deref(&self) -> &Stmt;
@@ -158,6 +165,7 @@ mod crate::clang {
158165
fn add_fn_defn(&mut self, DeclBuilder, Vec<Rc<Stmt>>);
159166
fn add_typedef(&mut self, Rc<SourceInfo>, Rc<Ident>, Rc<Type>);
160167
fn add_struct(&mut self, DeclBuilder);
168+
fn add_global_var(&mut self, Rc<SourceInfo>, Rc<Ident>, Rc<Type>, Option<Rc<Expr>>, bool);
161169
fn add_include(&mut self, Rc<SourceInfo>, u32, &SnippetMap);
162170

163171
fn mk_ghost_stmt(&mut self, Rc<SourceInfo>, u32, &SnippetMap) -> Rc<Stmt>;

cpp/impl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ using rust::std::rc::Rc;
1616
using rust::std::vec::Vec;
1717
using namespace rust::crate::clang;
1818
namespace ir = rust::crate::ir;
19+
using OptExpr = rust::core::option::Option<Rc<ir::Expr>>;
1920

2021
llvm::StringRef toStringRef(Ref<rust::Str> str) {
2122
return llvm::StringRef((char const *)str.as_ptr(), str.len());
@@ -829,6 +830,22 @@ class C2PulseConsumer : public ASTConsumer {
829830
// TODO: forward struct decls
830831
}
831832
return {};
833+
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
834+
auto loc = getRange(VD->getSourceRange());
835+
auto id = ctx.mk_ident(toStr(VD->getName()), loc.clone());
836+
auto ty = trQualType(VD->getType(), VD->getSourceRange());
837+
OptExpr init = VD->hasInit() ? OptExpr::Some(trRValue(VD->getInit()))
838+
: OptExpr::None();
839+
bool is_pure = false;
840+
for (auto attr : VD->getAttrs()) {
841+
if (auto ann = dyn_cast<AnnotateAttr>(attr);
842+
ann && ann->getAnnotation() == "c2pulse-pure" &&
843+
ann->args_size() == 0) {
844+
is_pure = true;
845+
}
846+
}
847+
return ctx.add_global_var(std::move(loc), std::move(id), std::move(ty),
848+
std::move(init), is_pure);
832849
}
833850

834851
reportUnsupported(D->getSourceRange(), getRange(D->getSourceRange()),

src/clang.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ impl<'a> Ctx<'a> {
119119
})
120120
}
121121

122+
fn add_global_var(
123+
&mut self,
124+
loc: Rc<SourceInfo>,
125+
name: Rc<Ident>,
126+
ty: Rc<Type>,
127+
init: Option<Rc<Expr>>,
128+
is_pure: bool,
129+
) {
130+
self.translation_unit.decls.push(Ast {
131+
loc,
132+
val: DeclT::GlobalVar(GlobalVar {
133+
name,
134+
ty,
135+
init,
136+
is_pure,
137+
}),
138+
})
139+
}
140+
122141
fn add_include(&mut self, loc: Rc<SourceInfo>, idx: u32, snippets: &SnippetMap) {
123142
match snippets.snippets.get(&idx) {
124143
Some(code) => self.translation_unit.decls.push(Ast {

src/env.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct Globals {
77
fns: HashMap<Rc<str>, FnDecl>,
88
typedefs: HashMap<Rc<str>, TypeDefn>,
99
structs: HashMap<Rc<str>, StructDefn>,
10+
vars: HashMap<Rc<str>, GlobalVar>,
1011
}
1112

1213
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -137,13 +138,20 @@ impl Env {
137138
.insert(decl.name.val.clone(), decl);
138139
}
139140

141+
pub fn push_global_var(&mut self, gv: GlobalVar) {
142+
Rc::make_mut(&mut self.globals)
143+
.vars
144+
.insert(gv.name.val.clone(), gv);
145+
}
146+
140147
pub fn push_decl(&mut self, decl: &Decl) {
141148
match &decl.val {
142149
DeclT::FnDefn(fn_defn) => self.push_fn_decl(fn_defn.decl.clone()),
143150
DeclT::FnDecl(fn_decl) => self.push_fn_decl(fn_decl.clone()),
144151
DeclT::Typedef(defn) => self.push_typedef(defn.clone()),
145152
DeclT::StructDefn(struct_defn) => self.push_struct(struct_defn.clone()),
146153
DeclT::IncludeDecl(_) => {}
154+
DeclT::GlobalVar(gv) => self.push_global_var(gv.clone()),
147155
}
148156
}
149157

@@ -187,8 +195,14 @@ impl Env {
187195
self.locals.get(&ident.val)
188196
}
189197

198+
pub fn lookup_global_var(&self, ident: &Ident) -> Option<&GlobalVar> {
199+
self.globals.vars.get(&ident.val)
200+
}
201+
190202
pub fn lookup_var_type(&self, ident: &Ident) -> Option<&Rc<Type>> {
191-
self.lookup_var(ident).map(|decl| &decl.ty)
203+
self.lookup_var(ident)
204+
.map(|decl| &decl.ty)
205+
.or_else(|| self.lookup_global_var(ident).map(|gv| &gv.ty))
192206
}
193207

194208
pub fn push_stmt(&mut self, stmt: &Stmt) {

src/ir/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,14 @@ pub struct IncludeDecl {
380380
pub code: InlineCode,
381381
}
382382

383+
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
384+
pub struct GlobalVar {
385+
pub name: Rc<Ident>,
386+
pub ty: Rc<Type>,
387+
pub init: Option<Rc<Expr>>,
388+
pub is_pure: bool,
389+
}
390+
383391
pub type Decl = Ast<DeclT>;
384392
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
385393
pub enum DeclT {
@@ -388,6 +396,7 @@ pub enum DeclT {
388396
Typedef(TypeDefn),
389397
StructDefn(StructDefn),
390398
IncludeDecl(IncludeDecl),
399+
GlobalVar(GlobalVar),
391400
}
392401

393402
#[derive(Debug, PartialEq, Eq, Hash, Clone)]

src/ir/pretty.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,28 @@ impl PrettyIR for IncludeDecl {
465465
}
466466
}
467467

468+
impl PrettyIR for GlobalVar {
469+
fn to_doc(&self) -> RcDoc<'_, ()> {
470+
let prefix = if self.is_pure {
471+
RcDoc::text("_pure ")
472+
} else {
473+
RcDoc::nil()
474+
};
475+
let init = match &self.init {
476+
Some(e) => RcDoc::text(" = ").append(e.to_doc()),
477+
None => RcDoc::nil(),
478+
};
479+
prefix
480+
.append(self.ty.to_doc())
481+
.append(RcDoc::line())
482+
.append(self.name.to_doc())
483+
.append(init)
484+
.append(";")
485+
.group()
486+
.nest(2)
487+
}
488+
}
489+
468490
impl PrettyIR for DeclT {
469491
fn to_doc(&self) -> RcDoc<'_, ()> {
470492
match self {
@@ -473,6 +495,7 @@ impl PrettyIR for DeclT {
473495
DeclT::Typedef(type_defn) => type_defn.to_doc(),
474496
DeclT::StructDefn(struct_defn) => struct_defn.to_doc(),
475497
DeclT::IncludeDecl(include_decl) => include_decl.to_doc(),
498+
DeclT::GlobalVar(global_var) => global_var.to_doc(),
476499
}
477500
}
478501
}

src/pass/check.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,17 @@ impl<'a> Checker<'a> {
368368

369369
fn check_var(&mut self, env: &Env, n: &Ident, needs_lvalue: bool) {
370370
match env.lookup_var(n) {
371-
None => self.report(format!("unknown local variable {}", n.val), &n.loc),
371+
None => match env.lookup_global_var(n) {
372+
Some(_) => {
373+
if needs_lvalue {
374+
self.report(
375+
format!("need lvalue, but global {} is rvalue", n.val),
376+
&n.loc,
377+
);
378+
}
379+
}
380+
None => self.report(format!("unknown local variable {}", n.val), &n.loc),
381+
},
372382
Some(ldecl) => {
373383
if ldecl.kind == LocalDeclKind::RValue && needs_lvalue {
374384
self.report(format!("need lvalue, but {} is rvalue", n.val), &n.loc);
@@ -529,6 +539,17 @@ impl<'a> Checker<'a> {
529539
}
530540
}
531541
DeclT::IncludeDecl(_) => {}
542+
DeclT::GlobalVar(GlobalVar {
543+
name: _,
544+
ty,
545+
init,
546+
is_pure: _,
547+
}) => {
548+
self.check_type(env, ty);
549+
if let Some(init) = init {
550+
self.check_rvalue(env, init);
551+
}
552+
}
532553
}
533554
}
534555

src/pass/elab.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,17 @@ impl<'a> Elaborator<'a> {
466466
}
467467
}
468468
DeclT::IncludeDecl(_) => {}
469+
DeclT::GlobalVar(GlobalVar {
470+
name: _,
471+
ty,
472+
init,
473+
is_pure: _,
474+
}) => {
475+
self.elab_type(env, Rc::make_mut(ty));
476+
if let Some(init) = init {
477+
self.elab_rvalue(env, Rc::make_mut(init));
478+
}
479+
}
469480
}
470481
}
471482
}

src/pass/emit.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,8 @@ impl<'a> Emitter<'a> {
480480
}) = env.lookup_var(x)
481481
{
482482
ExprKind::RValue(annotated(v, self.emit_var(x)))
483+
} else if env.lookup_global_var(x).is_some() {
484+
ExprKind::RValue(annotated(v, self.emit_var(x)))
483485
} else {
484486
ExprKind::LValue(annotated(v, self.emit_var(x)))
485487
}
@@ -2001,6 +2003,36 @@ impl<'a> Emitter<'a> {
20012003
)
20022004
}
20032005

2006+
fn emit_global_var(&mut self, env: &Env, gv: &GlobalVar) -> Doc {
2007+
if !gv.is_pure {
2008+
self.report(
2009+
"non-pure global variables are not yet supported".to_string(),
2010+
&gv.name.loc,
2011+
);
2012+
return Doc::nil();
2013+
}
2014+
let name = self.nm.emit(Name::Var(gv.name.val.clone()));
2015+
let ty = self.emit_type(env, &gv.ty);
2016+
match &gv.init {
2017+
Some(init) => {
2018+
let init_doc = self.emit_rvalue(env, init);
2019+
Doc::text("let ")
2020+
.append(name)
2021+
.append(" : ")
2022+
.append(ty)
2023+
.append(" = ")
2024+
.append(init_doc)
2025+
}
2026+
None => {
2027+
self.report(
2028+
"pure global variable must have an initializer".to_string(),
2029+
&gv.name.loc,
2030+
);
2031+
Doc::nil()
2032+
}
2033+
}
2034+
}
2035+
20042036
fn emit_decl(&mut self, env: &Env, decl: &Decl) -> Doc {
20052037
annotated(decl, {
20062038
match &decl.val {
@@ -2033,6 +2065,7 @@ impl<'a> Emitter<'a> {
20332065
DeclT::Typedef(typedef) => self.emit_typedef(env, typedef),
20342066
DeclT::StructDefn(struct_defn) => self.emit_structdefn(env, struct_defn),
20352067
DeclT::IncludeDecl(include_decl) => emit_inline_code(&include_decl.code),
2068+
DeclT::GlobalVar(gv) => self.emit_global_var(env, gv),
20362069
}
20372070
})
20382071
}

src/pass/prune.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ enum DeclName {
5959
Fn(Rc<str>),
6060
Struct(Rc<str>),
6161
Typedef(Rc<str>),
62+
GlobalVar(Rc<str>),
6263
Include(Rc<SourceInfo>),
6364
}
6465

@@ -238,6 +239,7 @@ fn decl_name(decl: &Decl) -> DeclName {
238239
DeclT::Typedef(type_defn) => DeclName::Typedef(type_defn.name.val.clone()),
239240
DeclT::StructDefn(struct_defn) => DeclName::Struct(struct_defn.name.val.clone()),
240241
DeclT::IncludeDecl(_) => DeclName::Include(decl.loc.clone()),
242+
DeclT::GlobalVar(gv) => DeclName::GlobalVar(gv.name.val.clone()),
241243
}
242244
}
243245

@@ -285,6 +287,18 @@ fn scan_translation_unit(deps: &mut Deps<DeclName>, tu: &TranslationUnit) {
285287
}
286288
}
287289
DeclT::IncludeDecl(_) => {}
290+
DeclT::GlobalVar(GlobalVar {
291+
name: _,
292+
ty,
293+
init,
294+
is_pure: _,
295+
}) => {
296+
let ds = deps.deps_for(n);
297+
scan_type(ds, ty);
298+
if let Some(init) = init {
299+
scan_expr(ds, init);
300+
}
301+
}
288302
}
289303
}
290304
}

0 commit comments

Comments
 (0)