Skip to content

Commit

Permalink
variable reassignment
Browse files Browse the repository at this point in the history
  • Loading branch information
andogq committed Aug 19, 2024
1 parent 8c48f14 commit fb99e8e
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 17 deletions.
36 changes: 31 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,44 @@ use lumina::compile_and_run;

fn main() {
let source = r#"
fn main() -> int {
let counter = 5;
fn fib1(n: int) -> int {
let a = 0;
let b = 1;
let count = 0;
loop {
if counter == 5 {
if count == n {
break;
}
let a = 3;
count = count + 1;
let temp = a;
a = b;
b = b + temp;
}
return a;
}
fn fib2(n: int) -> int {
if n == 0 || n == 1 {
return n;
}
return counter;
return fib2(n - 1) + fib2(n - 2);
}
fn main() -> int {
let result1 = fib1(19);
let result2 = fib2(19);
if result1 == result2 {
return result1;
} else {
return 0;
}
}"#;

let result = compile_and_run(source, true);
Expand Down
9 changes: 9 additions & 0 deletions src/repr/ast/base/expression/assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::*;
use crate::ast_node;

ast_node! {
typed struct Assign<TyInfo, FnIdentifier, IdentIdentifier> {
binding: IdentIdentifier,
value: Box<Expression<TyInfo, FnIdentifier, IdentIdentifier>>,
}
}
3 changes: 3 additions & 0 deletions src/repr/ast/base/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod assign;
mod block;
mod boolean;
mod call;
Expand All @@ -7,6 +8,7 @@ mod infix;
mod integer;
mod loop_block;

pub use assign::*;
pub use block::*;
pub use boolean::*;
pub use call::*;
Expand All @@ -30,6 +32,7 @@ ast_node!(
If(If<TyInfo, FnIdentifier, IdentIdentifier>),
Call(Call<TyInfo, FnIdentifier, IdentIdentifier>),
Loop(Loop<TyInfo, FnIdentifier, IdentIdentifier>),
Assign(Assign<TyInfo, FnIdentifier, IdentIdentifier>),
}
);

Expand Down
1 change: 1 addition & 0 deletions src/repr/ast/base/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ macro_rules! generate_ast {
pub type Loop = ast::Loop<$ty_info, $fn_identifier, $ident_identifier>;
pub type Infix = ast::Infix<$ty_info, $fn_identifier, $ident_identifier>;
pub type Integer = ast::Integer<$ty_info>;
pub type Assign = ast::Assign<$ty_info, $fn_identifier, $ident_identifier>;
pub type Expression = ast::Expression<$ty_info, $fn_identifier, $ident_identifier>;
pub type Function = ast::Function<$ty_info, $fn_identifier, $ident_identifier>;
pub type Program = ast::Program<$ty_info, $fn_identifier, $ident_identifier>;
Expand Down
8 changes: 7 additions & 1 deletion src/stage/lower_ir/lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ fn lower_expression(
// Continue on from where the loop ends
builder.goto_bb(loop_end);

None
Some(Value::Unit)
}
ast::Expression::Call(call) => {
let idx = call.name;
Expand All @@ -360,5 +360,11 @@ fn lower_expression(
.collect();
Some(Value::Triple(builder.add_triple(Triple::Call(idx, params))))
}
ast::Expression::Assign(assign) => {
let value = lower_expression(compiler, builder, &assign.value).unwrap();
builder.add_triple(Triple::Assign(assign.binding, value));

Some(Value::Unit)
}
}
}
36 changes: 36 additions & 0 deletions src/stage/parse/expression/e_assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pub use super::*;

pub fn parse_assign(compiler: &mut Compiler, tokens: &mut Lexer<'_>) -> Result<Assign, ParseError> {
let (binding, span_start) = match tokens.next_spanned().unwrap() {
(Token::Ident(ident), span) => (ident, span),
(token, _) => {
return Err(ParseError::ExpectedToken {
expected: Box::new(Token::Ident(String::new())),
found: Box::new(token),
reason: "assign must start with ident".to_string(),
});
}
};

let binding = compiler.symbols.get_or_intern(binding);

match tokens.next_token().unwrap() {
Token::Eq => (),
token => {
return Err(ParseError::ExpectedToken {
expected: Box::new(Token::Eq),
found: Box::new(token),
reason: "equals sign following binding for assign".to_string(),
});
}
}

let value = parse_expression(compiler, tokens, Precedence::Lowest)?;

Ok(Assign {
span: span_start.start..value.span().end,
binding,
value: Box::new(value),
ty_info: None,
})
}
2 changes: 1 addition & 1 deletion src/stage/parse/expression/e_boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ mod test {
let mut tokens = source.into();
let _ = parse_boolean(&mut Compiler::default(), &mut tokens);

assert_eq!(tokens.0.count(), 1);
assert_eq!(tokens.count(), 1);
}
}
2 changes: 1 addition & 1 deletion src/stage/parse/expression/e_ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ mod test {
let mut tokens = source.into();
let _ = parse_ident(&mut Compiler::default(), &mut tokens);

assert_eq!(tokens.0.count(), 1);
assert_eq!(tokens.count(), 1);
}
}
2 changes: 1 addition & 1 deletion src/stage/parse/expression/e_integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ mod test {
fn single_token(#[case] source: &str) {
let mut tokens = source.into();
let _ = parse_integer(&mut Compiler::default(), &mut tokens);
assert_eq!(tokens.0.count(), 1);
assert_eq!(tokens.count(), 1);
}
}
7 changes: 6 additions & 1 deletion src/stage/parse/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::iter;

use e_assign::parse_assign;
use e_loop::parse_loop;

use super::*;
Expand All @@ -8,6 +9,7 @@ use self::{
e_boolean::parse_boolean, e_ident::parse_ident, e_if::parse_if, e_integer::parse_integer,
};

mod e_assign;
mod e_boolean;
mod e_ident;
mod e_if;
Expand Down Expand Up @@ -36,8 +38,11 @@ impl Precedence {
}

fn parse_prefix(compiler: &mut Compiler, tokens: &mut Lexer<'_>) -> Result<Expression, ParseError> {
match tokens.peek_token().unwrap() {
match tokens.peek_token().unwrap().clone() {
Token::Integer(_) => Ok(Expression::Integer(parse_integer(compiler, tokens)?)),
Token::Ident(_) if matches!(tokens.double_peek_token(), Some(Token::Eq)) => {
Ok(Expression::Assign(parse_assign(compiler, tokens)?))
}
Token::Ident(_) => Ok(Expression::Ident(parse_ident(compiler, tokens)?)),
Token::True => Ok(Expression::Boolean(parse_boolean(compiler, tokens)?)),
Token::False => Ok(Expression::Boolean(parse_boolean(compiler, tokens)?)),
Expand Down
50 changes: 43 additions & 7 deletions src/stage/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,19 @@ pub fn parse(compiler: &mut Compiler, source: &str) -> Result<Program, ParseErro
Ok(program)
}

struct Lexer<'source>(Peekable<logos::SpannedIter<'source, Token>>);
struct Lexer<'source> {
next: Option<(Token, Span)>,
lexer: Peekable<logos::SpannedIter<'source, Token>>,
}

impl<'source> Lexer<'source> {
fn new(lexer: logos::Lexer<'source, Token>) -> Self {
Self {
lexer: lexer.spanned().peekable(),
next: None,
}
}

fn next_token(&mut self) -> Option<Token> {
self.next_spanned().map(|(token, _)| token)
}
Expand All @@ -90,13 +100,39 @@ impl<'source> Lexer<'source> {
}

fn next_spanned(&mut self) -> Option<(Token, Span)> {
self.0.next().map(|(result, span)| (result.unwrap(), span))
self.next.take().or_else(|| self.next())
}

fn peek_spanned(&mut self) -> Option<(&Token, &Span)> {
self.0
self.next
.as_ref()
.map(|(token, span)| (token, span))
.or_else(|| {
self.lexer
.peek()
.map(|(result, span)| (result.as_ref().unwrap(), span))
})
}

fn double_peek_token(&mut self) -> Option<&Token> {
if self.next.is_none() {
self.next = self.next();
}

self.lexer
.peek()
.map(|(result, span)| (result.as_ref().unwrap(), span))
.map(|(result, _)| result.as_ref().unwrap())
}

fn next(&mut self) -> Option<(Token, Span)> {
self.lexer
.next()
.map(|(result, span)| (result.unwrap(), span))
}

#[allow(dead_code)]
fn count(self) -> usize {
self.lexer.count() + self.next.map(|_| 1).unwrap_or(0)
}
}

Expand All @@ -108,20 +144,20 @@ impl<'source> From<&'source str> for Lexer<'source> {

impl<'source> From<logos::Lexer<'source, Token>> for Lexer<'source> {
fn from(lexer: logos::Lexer<'source, Token>) -> Self {
Self(lexer.spanned().peekable())
Self::new(lexer)
}
}

impl<'source> Deref for Lexer<'source> {
type Target = Peekable<logos::SpannedIter<'source, Token>>;

fn deref(&self) -> &Self::Target {
&self.0
&self.lexer
}
}

impl<'source> DerefMut for Lexer<'source> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
&mut self.lexer
}
}
30 changes: 30 additions & 0 deletions src/stage/type_check/expression/assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::{compiler::Compiler, util::scope::Scope};

use super::*;

impl parse_ast::Assign {
pub fn ty_solve(self, compiler: &mut Compiler, scope: &mut Scope) -> Result<Assign, TyError> {
// Work out what type the variable has to be
let (binding, ty) = scope
.resolve(self.binding)
.ok_or(TyError::SymbolNotFound(self.binding))?;

let value = self.value.ty_solve(compiler, scope)?;

let value_ty = value.get_ty_info().ty;

if value_ty != ty {
return Err(TyError::Mismatch(ty, value_ty));
}

Ok(Assign {
binding,
ty_info: TyInfo {
ty: Ty::Unit,
return_ty: value.get_ty_info().return_ty,
},
value: Box::new(value),
span: self.span,
})
}
}
2 changes: 2 additions & 0 deletions src/stage/type_check/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{compiler::Compiler, util::scope::Scope};

use super::*;

mod assign;
mod block;
mod boolean;
mod call;
Expand All @@ -26,6 +27,7 @@ impl parse_ast::Expression {
parse_ast::Expression::If(e) => Expression::If(e.ty_solve(compiler, scope)?),
parse_ast::Expression::Loop(e) => Expression::Loop(e.ty_solve(compiler, scope)?),
parse_ast::Expression::Call(e) => Expression::Call(e.ty_solve(compiler, scope)?),
parse_ast::Expression::Assign(e) => Expression::Assign(e.ty_solve(compiler, scope)?),
})
}
}

0 comments on commit fb99e8e

Please sign in to comment.