Skip to content

Commit 097cebb

Browse files
committed
feat(compiler): variadic list function for constructing sequences
1 parent 6562a12 commit 097cebb

File tree

3 files changed

+173
-87
lines changed

3 files changed

+173
-87
lines changed

core/compiler/src/compile.rs

Lines changed: 115 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ use crate::{
3333
solver::{LinearExpr, Solver},
3434
};
3535

36-
pub const BUILTINS: [&str; 11] = [
36+
pub const BUILTINS: [&str; 12] = [
37+
"list",
3738
"cons",
3839
"head",
3940
"tail",
@@ -523,20 +524,20 @@ impl Ty {
523524

524525
/// Computes the least upper bound (LUB) of self and other.
525526
/// For use in type promotion.
526-
pub fn lub(&self, other: &Self) -> Option<Self> {
527+
pub fn lub(&self, other: &Self) -> Self {
527528
match (self, other) {
528529
// Unknown promotes to any type.
529-
(Ty::Unknown, other) | (other, Ty::Unknown) => Some(other.clone()),
530+
(Ty::Unknown, other) | (other, Ty::Unknown) => other.clone(),
531+
// At least one Any results in Any.
532+
(Ty::Any, _) | (_, Ty::Any) => Ty::Any,
530533
// SeqNil promotes to any sequence type.
531-
(Ty::SeqNil, Ty::Seq(inner)) | (Ty::Seq(inner), Ty::SeqNil) => {
532-
Some(Ty::Seq(inner.clone()))
533-
}
534-
// No other types promote.
534+
(Ty::SeqNil, Ty::Seq(inner)) | (Ty::Seq(inner), Ty::SeqNil) => Ty::Seq(inner.clone()),
535+
// Mismatched types promote to any.
535536
(a, b) => {
536537
if a == b {
537-
Some(a.clone())
538+
a.clone()
538539
} else {
539-
None
540+
Ty::Any
540541
}
541542
}
542543
}
@@ -1212,16 +1213,7 @@ impl<'a> AstTransformer for VarIdTyPass<'a> {
12121213
kind: StaticErrorKind::IfCondNotBool,
12131214
});
12141215
}
1215-
let lub_ty = then_ty.lub(&else_ty);
1216-
if let Some(lub_ty) = lub_ty {
1217-
lub_ty
1218-
} else {
1219-
self.errors.push(StaticError {
1220-
span: self.span(input.span),
1221-
kind: StaticErrorKind::BranchesDifferentTypes,
1222-
});
1223-
then_ty
1224-
}
1216+
then_ty.lub(&else_ty)
12251217
}
12261218

12271219
fn dispatch_match_expr(
@@ -1251,14 +1243,7 @@ impl<'a> AstTransformer for VarIdTyPass<'a> {
12511243
}
12521244

12531245
if let Some(ref inner) = lub_ty {
1254-
if let Some(lub) = inner.lub(&arm.expr.ty()) {
1255-
lub_ty = Some(lub);
1256-
} else {
1257-
self.errors.push(StaticError {
1258-
span: self.span(arm.expr.span()),
1259-
kind: StaticErrorKind::BranchesDifferentTypes,
1260-
});
1261-
}
1246+
lub_ty = Some(inner.lub(&arm.expr.ty()));
12621247
} else {
12631248
lub_ty = Some(arm.expr.ty());
12641249
}
@@ -1339,65 +1324,57 @@ impl<'a> AstTransformer for VarIdTyPass<'a> {
13391324
let left_ty = left.ty();
13401325
let right_ty = right.ty();
13411326
let lub_ty = left_ty.lub(&right_ty);
1342-
if let Some(lub_ty) = lub_ty {
1343-
if left_ty == Ty::Float
1344-
&& (input.op == ComparisonOp::Eq || input.op == ComparisonOp::Ne)
1345-
{
1346-
self.errors.push(StaticError {
1347-
span: self.span(input.span),
1348-
kind: StaticErrorKind::FloatEquality,
1349-
});
1350-
}
1351-
if matches!(left_ty, Ty::Enum(_))
1352-
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1353-
{
1354-
self.errors.push(StaticError {
1355-
span: self.span(input.span),
1356-
kind: StaticErrorKind::EnumsNotOrd,
1357-
});
1358-
}
1359-
if matches!(left_ty, Ty::Nil)
1360-
&& matches!(right_ty, Ty::Nil)
1361-
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1362-
{
1363-
self.errors.push(StaticError {
1364-
span: self.span(input.span),
1365-
kind: StaticErrorKind::NilNotOrd,
1366-
});
1367-
}
1368-
if matches!(left_ty, Ty::SeqNil)
1369-
&& matches!(right_ty, Ty::SeqNil)
1370-
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1371-
{
1372-
self.errors.push(StaticError {
1373-
span: self.span(input.span),
1374-
kind: StaticErrorKind::SeqNilNotOrd,
1375-
});
1376-
}
1377-
if matches!(lub_ty, Ty::Seq(_))
1378-
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1379-
&& !(left_ty == Ty::SeqNil || right_ty == Ty::SeqNil)
1380-
{
1381-
self.errors.push(StaticError {
1382-
span: self.span(input.span),
1383-
kind: StaticErrorKind::SeqMustCompareEqSeqNil,
1384-
});
1385-
}
1386-
if !matches!(
1387-
left_ty,
1388-
Ty::Float | Ty::Int | Ty::Enum(_) | Ty::Seq(_) | Ty::Nil | Ty::SeqNil
1389-
) {
1390-
self.errors.push(StaticError {
1391-
span: self.span(input.span),
1392-
kind: StaticErrorKind::ComparisonInvalidType,
1393-
});
1394-
}
1395-
} else {
1327+
if left_ty == Ty::Float && (input.op == ComparisonOp::Eq || input.op == ComparisonOp::Ne) {
13961328
self.errors.push(StaticError {
13971329
span: self.span(input.span),
1398-
kind: StaticErrorKind::BinOpMismatchedTypes,
1330+
kind: StaticErrorKind::FloatEquality,
1331+
});
1332+
}
1333+
if matches!(left_ty, Ty::Enum(_))
1334+
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1335+
{
1336+
self.errors.push(StaticError {
1337+
span: self.span(input.span),
1338+
kind: StaticErrorKind::EnumsNotOrd,
13991339
});
14001340
}
1341+
if matches!(left_ty, Ty::Nil)
1342+
&& matches!(right_ty, Ty::Nil)
1343+
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1344+
{
1345+
self.errors.push(StaticError {
1346+
span: self.span(input.span),
1347+
kind: StaticErrorKind::NilNotOrd,
1348+
});
1349+
}
1350+
if matches!(left_ty, Ty::SeqNil)
1351+
&& matches!(right_ty, Ty::SeqNil)
1352+
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1353+
{
1354+
self.errors.push(StaticError {
1355+
span: self.span(input.span),
1356+
kind: StaticErrorKind::SeqNilNotOrd,
1357+
});
1358+
}
1359+
if matches!(lub_ty, Ty::Seq(_))
1360+
&& (input.op != ComparisonOp::Eq && input.op != ComparisonOp::Ne)
1361+
&& !(left_ty == Ty::SeqNil || right_ty == Ty::SeqNil)
1362+
{
1363+
self.errors.push(StaticError {
1364+
span: self.span(input.span),
1365+
kind: StaticErrorKind::SeqMustCompareEqSeqNil,
1366+
});
1367+
}
1368+
if !matches!(
1369+
left_ty,
1370+
Ty::Float | Ty::Int | Ty::Enum(_) | Ty::Seq(_) | Ty::Nil | Ty::SeqNil
1371+
) {
1372+
self.errors.push(StaticError {
1373+
span: self.span(input.span),
1374+
kind: StaticErrorKind::ComparisonInvalidType,
1375+
});
1376+
}
1377+
14011378
Ty::Bool
14021379
}
14031380

@@ -1530,6 +1507,24 @@ impl<'a> AstTransformer for VarIdTyPass<'a> {
15301507
(None, Ty::SeqNil)
15311508
}
15321509
}
1510+
"list" => {
1511+
self.typecheck_kwargs(&args.kwargs, IndexMap::default());
1512+
if args.posargs.is_empty() {
1513+
self.errors.push(StaticError {
1514+
span: self.span(input.span),
1515+
kind: StaticErrorKind::EmptyListConstructor,
1516+
});
1517+
(None, Ty::Nil)
1518+
} else {
1519+
let elem_ty = args
1520+
.posargs
1521+
.iter()
1522+
.map(Expr::ty)
1523+
.reduce(|acc, e| acc.lub(&e))
1524+
.unwrap();
1525+
(None, Ty::Seq(Box::new(elem_ty)))
1526+
}
1527+
}
15331528
"head" => {
15341529
self.assert_eq_arity(input.span, args.posargs.len(), 1);
15351530
if args.posargs.len() == 1 {
@@ -2844,7 +2839,12 @@ impl<'a> ExecPass<'a> {
28442839
Expr::BinOp(b) => {
28452840
let lhs = self.visit_expr(loc, &b.left);
28462841
let rhs = self.visit_expr(loc, &b.right);
2847-
PartialEvalState::BinOp(PartialBinOp { lhs, rhs, op: b.op })
2842+
PartialEvalState::BinOp(PartialBinOp {
2843+
lhs,
2844+
rhs,
2845+
op: b.op,
2846+
expr: b.clone(),
2847+
})
28482848
}
28492849
Expr::UnaryOp(u) => {
28502850
let operand = self.visit_expr(loc, &u.operand);
@@ -3179,6 +3179,23 @@ impl<'a> ExecPass<'a> {
31793179
false
31803180
}
31813181
}
3182+
"list" => {
3183+
let vals = c
3184+
.state
3185+
.posargs
3186+
.iter()
3187+
.map(|v| self.values[v].get_ready())
3188+
.collect::<Option<Vec<_>>>();
3189+
if let Some(vals) = vals {
3190+
self.values.insert(
3191+
vid,
3192+
Defer::Ready(Value::Seq(vals.iter().map(|v| (*v).clone()).collect())),
3193+
);
3194+
true
3195+
} else {
3196+
false
3197+
}
3198+
}
31823199
"head" => {
31833200
if let Defer::Ready(head) = &self.values[&c.state.posargs[0]] {
31843201
let val = match head {
@@ -3473,7 +3490,15 @@ impl<'a> ExecPass<'a> {
34733490
self.values.insert(vid, DeferValue::Ready(Value::Int(res)));
34743491
true
34753492
}
3476-
_ => todo!(),
3493+
_ => {
3494+
let span = self.span(&vref.loc, bin_op.expr.span);
3495+
self.errors.push(ExecError {
3496+
span: Some(span.clone()),
3497+
cell: vref.loc.cell,
3498+
kind: ExecErrorKind::InvalidType,
3499+
});
3500+
return Err(());
3501+
}
34773502
}
34783503
} else {
34793504
false
@@ -4336,6 +4361,9 @@ pub enum StaticErrorKind {
43364361
/// Incorrect type category.
43374362
#[error("expected type category {expected}, found {found:?}")]
43384363
IncorrectTyCategory { found: Ty, expected: String },
4364+
/// Empty list constructor.
4365+
#[error("list constructors cannot be empty (use `[]` for an empty list)")]
4366+
EmptyListConstructor,
43394367
/// Called a function or cell with the wrong number of positional arguments.
43404368
#[error("expected {expected} position arguments, found {found}")]
43414369
CallIncorrectPositionalArity { expected: usize, found: usize },
@@ -4462,7 +4490,7 @@ enum PartialEvalState<T: AstMetadata> {
44624490
If(Box<PartialIfExpr<T>>),
44634491
Match(Box<PartialMatchExpr<T>>),
44644492
Comparison(Box<PartialComparisonExpr<T>>),
4465-
BinOp(PartialBinOp),
4493+
BinOp(PartialBinOp<T>),
44664494
UnaryOp(PartialUnaryOp<T>),
44674495
Call(Box<PartialCallExpr<T>>),
44684496
FieldAccess(Box<PartialFieldAccessExpr<T>>),
@@ -4487,10 +4515,11 @@ struct PartialConstraint {
44874515
}
44884516

44894517
#[derive(Debug, Clone)]
4490-
struct PartialBinOp {
4518+
struct PartialBinOp<T: AstMetadata> {
44914519
lhs: ValueId,
44924520
rhs: ValueId,
44934521
op: BinOp,
4522+
expr: Box<BinOpExpr<Substr, T>>,
44944523
}
44954524

44964525
#[derive(Debug, Clone)]

core/compiler/src/lib.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod tests {
2020
use const_format::concatcp;
2121
use gds21::GdsUnits;
2222

23-
use crate::compile::{compile, CellArg, CompileInput};
23+
use crate::compile::{CellArg, CompileInput, compile};
2424
const EPSILON: f64 = 1e-10;
2525

2626
const EXAMPLES_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../examples");
@@ -58,6 +58,7 @@ mod tests {
5858
const ARGON_TEXT: &str = concatcp!(EXAMPLES_DIR, "/text/lib.ar");
5959
const ARGON_ANY_TYPE: &str = concatcp!(EXAMPLES_DIR, "/any_type/lib.ar");
6060
const ARGON_SEQ_INDEX: &str = concatcp!(EXAMPLES_DIR, "/seq_index/lib.ar");
61+
const ARGON_SEQ_CONSTRUCTOR: &str = concatcp!(EXAMPLES_DIR, "/seq_constructor/lib.ar");
6162

6263
#[test]
6364
fn argon_scopes() {
@@ -753,4 +754,31 @@ mod tests {
753754
assert_relative_eq!(r.x1.0, 300., epsilon = EPSILON);
754755
assert_relative_eq!(r.y1.0, 500., epsilon = EPSILON);
755756
}
757+
758+
#[test]
759+
fn argon_seq_constructor() {
760+
let o = parse_workspace_with_std(ARGON_SEQ_CONSTRUCTOR);
761+
assert!(o.static_errors().is_empty());
762+
let ast = o.ast();
763+
let cells = compile(
764+
&ast,
765+
CompileInput {
766+
cell: &["top"],
767+
args: Vec::new(),
768+
lyp_file: &PathBuf::from(BASIC_LYP),
769+
},
770+
);
771+
println!("{cells:#?}");
772+
773+
let cells = cells.unwrap_valid();
774+
let cell = &cells.cells[&cells.top];
775+
assert_eq!(cell.objects.len(), 3);
776+
777+
let r = cell.objects.iter().find_map(|(_, v)| v.get_rect()).unwrap();
778+
assert_eq!(r.layer.as_ref().unwrap(), "met1");
779+
assert_relative_eq!(r.x0.0, 200., epsilon = EPSILON);
780+
assert_relative_eq!(r.y0.0, 0., epsilon = EPSILON);
781+
assert_relative_eq!(r.x1.0, 300., epsilon = EPSILON);
782+
assert_relative_eq!(r.y1.0, 500., epsilon = EPSILON);
783+
}
756784
}

examples/seq_constructor/lib.ar

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
cell bot() {
3+
let met1 = rect("met1", x0=0., y0=0., x1=100., y1=500.);
4+
}
5+
6+
fn getx(inst_: Any) -> Float {
7+
inst_.x
8+
}
9+
10+
fn double(cell_: Any) -> [Any] {
11+
let lst = list(100., 200., 300., 400.);
12+
let i1 = inst(cell_, x=0., y=0.);
13+
let i2 = inst(cell_, x=getx(i1) + lst[2] - 100., y=0.);
14+
list(i1, i2)
15+
}
16+
17+
fn index01(one: Bool) -> Int {
18+
if one {
19+
1
20+
} else {
21+
0
22+
}
23+
}
24+
25+
cell top() {
26+
let bot_cell = bot();
27+
let arr = double(bot_cell);
28+
arr[index01(true)].met1!;
29+
}

0 commit comments

Comments
 (0)