Skip to content

Commit

Permalink
add record tests and fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
cecelot committed Feb 3, 2024
1 parent 50ef320 commit 51e00e4
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: kyanite-core/src/pass/typecheck.rs
source: crates/kyac/src/pass/typecheck.rs
expression: pass.errors
---
[
Expand Down Expand Up @@ -32,7 +32,7 @@ expression: pass.errors
span: Span {
line: 28,
column: 26,
length: 20,
length: 3,
},
text: "expression of type Bar",
},
Expand Down
4 changes: 3 additions & 1 deletion crates/kyac/src/ast/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{

pub trait Combined {
fn span(&self) -> Span {
assert!(self.end() >= self.start(), "likely a multi-line span");
Span::new(self.line(), self.start(), self.end() - self.start())
}
fn start(&self) -> usize;
Expand Down Expand Up @@ -74,7 +75,8 @@ impl Combined for Expr {
Expr::Int(i) => i.token.span.column + i.token.span.length,
Expr::Float(f) => f.token.span.column + f.token.span.length,
Expr::Bool(b) => b.token.span.column + b.token.span.length,
Expr::Init(init) => init.parens.1.span.column + 1,
// TODO: support multi-line spans
Expr::Init(init) => init.name.span.column + init.name.span.length,
}
}

Expand Down
4 changes: 3 additions & 1 deletion crates/kyac/src/backend/kyir/arch/amd64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ impl Frame for Amd64 {
self.offset -= i64::try_from(match ty {
Some(Type::UserDefined(ty)) => {
let rec = symbols.get(ty).unwrap().record();
rec.fields.len() * Self::word_size()
// The magic +1 is here because the first word is used to
// store the address of the record in the frame.
(rec.fields.len() + 1) * Self::word_size()
}
_ => 8,
})
Expand Down
23 changes: 22 additions & 1 deletion crates/kyac/src/backend/kyir/arch/amd64/red_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,32 @@ pub fn run<F: Frame>(codegen: &mut Codegen<F>) {
AsmInstr::new(Instr::oper(
Opcode::Sub,
F::registers().stack.into(),
"$16".into(),
// Not sure if we actually need to align the stack to a multiple of 16 bytes, but we do it anyway.
format!("${}", next_multiple_of(fun.offset().abs(), 16)),
None,
)),
);
}
}
}
}

/// Stolen from <https://github.com/rust-lang/rust/issues/88581> until this is in stable.
fn next_multiple_of(n: i64, rhs: i64) -> i64 {
if rhs == -1 {
return n;
}

let r = n % rhs;
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
r + rhs
} else {
r
};

if m == 0 {
n
} else {
n + (rhs - m)
}
}
12 changes: 9 additions & 3 deletions crates/kyac/src/backend/kyir/translate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,10 @@ impl Translate<Expr> for ast::node::Access {
let last = self.chain.last().unwrap().ident().name.to_string();
let (index, _) = flat
.iter()
.rev()
.enumerate()
.find(|(_, (name, _))| name == &last)
.unwrap();
.expect("field access for non-terminal fields is not yet supported");
frame.get(&parent, Some(temp), Some(index))
}
}
Expand All @@ -183,7 +184,9 @@ impl Translate<Expr> for ast::node::Init {
let id = translator.function.unwrap();
let frame = translator.functions.get_mut(&id).unwrap();
frame.allocate(translator.symbols, &name, Some(&ty));
let begin = frame.get_offset(&name);
// We begin at the current frame's offset - one word size (since the current frame's offset is used
// to store the start address of the actual fields)
let begin = frame.get_offset(&name) - i64::try_from(F::word_size()).unwrap();
let end = begin - i64::try_from((initializers.len() - 1) * F::word_size()).unwrap();
let stmts: Vec<Stmt> = initializers
.into_iter()
Expand All @@ -199,7 +202,10 @@ impl Translate<Expr> for ast::node::Init {
)
})
.collect();
// Evaluate the initializers, then return start address of initialized memory for record
// Evaluate the initializers, then return start address of initialized memory for record.
// This doesn't technically need to exist since the frame already stores this information.
// [-8, -16, -32, ...]
// [ start address, field 1, field 2, ...]
ESeq::wrapped(Stmt::from(&stmts[..]), Const::<i64>::int(begin))
}
}
Expand Down
21 changes: 21 additions & 0 deletions crates/kyanite/tests/kyir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,24 @@ fn called_nested_loop() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(res.output, "5\n6\n7\n8\n9\n");
Ok(())
}

#[test]
fn simple_record() -> Result<(), Box<dyn std::error::Error>> {
let res = run("kyir/simple-record.kya")?;
assert_eq!(res.output, "3\n");
Ok(())
}

#[test]
fn record_with_addition() -> Result<(), Box<dyn std::error::Error>> {
let res = run("kyir/record-with-addition.kya")?;
assert_eq!(res.output, "7\n");
Ok(())
}

#[test]
fn nested_records() -> Result<(), Box<dyn std::error::Error>> {
let res = run("kyir/nested-records.kya")?;
assert_eq!(res.output, "1\n2\ntrue\n");
Ok(())
}
22 changes: 22 additions & 0 deletions examples/kyir/nested-records.kya
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
rec Coordinate {
pos: Position,
is_fun: bool
}

rec Position {
x: int,
y: int
}

fun main() {
let c: Coordinate = Coordinate:init(
pos: Position:init(x: 1, y: 2),
is_fun: true
);
let x: int = c.pos.x;
let y: int = c.pos.y;
println_int(x);
println_int(y);
let is_fun: bool = c.is_fun;
println_bool(is_fun);
}
13 changes: 13 additions & 0 deletions examples/kyir/record-with-addition.kya
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
rec Coordinate {
x: int,
y: int
}

fun main() {
let c: Coordinate = Coordinate:init(
x: 3,
y: 4
);
let sum: int = c.x + c.y;
println_int(sum);
}
13 changes: 13 additions & 0 deletions examples/kyir/simple-record.kya
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
rec Coordinate {
x: int,
y: int
}

fun main() {
let c: Coordinate = Coordinate:init(
x: 3,
y: 4
);
let z: int = c.x;
println_int(z);
}

0 comments on commit 51e00e4

Please sign in to comment.