diff --git a/README.md b/README.md index 3d6fdb1..a9a3c2f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # nanilang Repositório para o Trabalho de Implementação de Linguagens de Programação + +## Not Working + +- Array initialization +- Array of string +- Read +- Ternary diff --git a/examples/arr.nani b/examples/arr.nani index 40a5f49..c112648 100644 --- a/examples/arr.nani +++ b/examples/arr.nani @@ -2,15 +2,15 @@ let i[2] = { 1, 2 }: int; let j[2] = { false, true }: bool; def array_with_expr_index() { - let i[3] = { 3, 4, 5 }: int; - let k: int; + var i[3] = { 3, 4, 5 }: int; + var k: int; write i[k], i[k + 1]; return; } def main(): int { - let i[2] = { 3, 4 }: int; - let j[2] = { false, true }: bool; + var i[2] = { 3, 4 }: int; + var j[2] = { false, true }: bool; write i[0], i[1]; write j[0], j[1]; diff --git a/examples/arr2.nani b/examples/arr2.nani new file mode 100644 index 0000000..faf994c --- /dev/null +++ b/examples/arr2.nani @@ -0,0 +1,4 @@ +def main(v[]: int; a: int): int { + var x = v[a] : int; + a++; +} diff --git a/examples/aspas1aspas.nani b/examples/aspas1aspas.nani new file mode 100644 index 0000000..a3a2bb2 --- /dev/null +++ b/examples/aspas1aspas.nani @@ -0,0 +1,4 @@ +def main(): int { + var i: int; + i = "1"; +} diff --git a/examples/fibonacci.nani b/examples/fibonacci.nani new file mode 100644 index 0000000..948dd97 --- /dev/null +++ b/examples/fibonacci.nani @@ -0,0 +1,11 @@ +def main(): int { + var a = 1, b = 1, aux, i: int; + write "fibonacci"; + while (b <= 100){ + write a; + aux = a; + a = b; + b = b + aux; + } + return 0; +} diff --git a/examples/for.nani b/examples/for.nani index f42db81..9ad3904 100644 --- a/examples/for.nani +++ b/examples/for.nani @@ -1,5 +1,5 @@ def main(): int { - let i: int; + var i: int; for (i = 0; i < 10; i += 1) { write i; diff --git a/examples/ifs.nani b/examples/ifs.nani index 8d34215..3a5289a 100644 --- a/examples/ifs.nani +++ b/examples/ifs.nani @@ -1,8 +1,8 @@ def main(): int { - let x = true: bool; + var x = true: bool; if (x == true) { - let i: int; + var i: int; read i; write i + 10; } else { @@ -11,3 +11,4 @@ def main(): int { return 0; } + diff --git a/examples/jarroba.nani b/examples/jarroba.nani new file mode 100644 index 0000000..0ba8e9f --- /dev/null +++ b/examples/jarroba.nani @@ -0,0 +1,3 @@ +def main(): int { + var j@: int; +} diff --git a/examples/ternary.nani b/examples/ternary.nani new file mode 100644 index 0000000..fd3035e --- /dev/null +++ b/examples/ternary.nani @@ -0,0 +1,12 @@ +def main(): int { + var a = false: bool; + + var b = (a ? 1 : 2): int; + var c: int; + c = false ? 10 : 20; + + write b; + write c; + + return 0; +} diff --git a/rustfmt.toml b/rustfmt.toml index c7a80ee..425954b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -49,7 +49,7 @@ use_field_init_shorthand = false force_explicit_abi = true condense_wildcard_suffixes = false color = "Auto" -required_version = "0.99.6" +required_version = "1.0.0" unstable_features = false disable_all_formatting = false skip_children = false diff --git a/src/ast.rs b/src/ast.rs index 2ce458e..1ac3742 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,6 +1,10 @@ use llvm::LLVMIntPredicate; use std::fmt; +use codespan::{ByteIndex, Span}; + +pub type Location = Span; + #[macro_export] macro_rules! flatten { ($v:ident) => { @@ -24,14 +28,15 @@ fn get_tabs(f: &fmt::Formatter) -> (usize, String) { #[derive(Clone, PartialEq)] pub enum Expr { - Number(u64), - Variable(Variable), - True, - False, - Call(String, Option>>), - Op(Box, Opcode, Box), - Right(Opcode, Box), - Ternary(Box, Box, Box), + Number(u64, Location), + StringLitteral(String, Location), + Variable(Variable, Location), + True(Location), + False(Location), + Call(String, Option>>, Location), + Op(Box, Opcode, Box, Location), + Right(Opcode, Box, Location), + Ternary(Box, Box, Box, Location), } #[derive(Clone, PartialEq)] @@ -66,48 +71,68 @@ pub enum Type { Int, Bool, Str, + Void, + Agg(Box), +} + +impl Default for Type { + fn default() -> Type { + Type::Void + } } #[derive(Clone, PartialEq)] pub enum Variable { - Single(String), - Array(String, Box), + Single(String, Location), + Array(String, Box, Location), } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub enum Decl { - Single(String, Type, Option>), - Array(String, Type, u64, Option>>), - Func(String, Option, Option>, Block), + Single(String, Type, Option>, Location), + Array(String, Type, u64, Option>>, Location), + Func( + String, + Option, + Option>, + Block, + Location, + ), } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub enum FuncParam { - Single(String, Type), - Array(String, Type), + Single(String, Type, Location), + Array(String, Type, Location), } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub enum Stmt { - Attr(Variable, Box), - Stop, - Skip, - Return(Option>), - Read(Variable), - Write(Vec>), - Call(String, Option>>), - If(Box, Block, Vec<(Box, Block)>, Option), - While(Box, Block), - For(Box, Box, Box, Block), + Attr(Variable, Box, Location), + Stop(Location), + Skip(Location), + Return(Option>, Location), + Read(Variable, Location), + Write(Vec>, Location), + Call(String, Option>>, Location), + If( + Box, + Block, + Vec<(Box, Block)>, + Option, + Location, + ), + While(Box, Block, Location), + For(Box, Box, Box, Block, Location), } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub enum Either { Left(A), Right(B), } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] pub struct Block { pub decl: Vec, pub commands: Vec>, @@ -117,26 +142,29 @@ impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (width, tabs) = get_tabs(f); match self { - Expr::Number(i) => write!(f, "${:?}", i), - Expr::Variable(v) => { + Expr::Number(i, _) => write!(f, "${:?}", i), + Expr::StringLitteral(s, _) => write!(f, "${:?}", s), + Expr::Variable(v, _) => { write!(f, "{tabs}{:width$?}", v, tabs = tabs, width = width + 1) } - Expr::True => write!(f, "$true"), - Expr::False => write!(f, "$false"), + Expr::True(_) => write!(f, "$true"), + Expr::False(_) => write!(f, "$false"), - Expr::Call(fun, Some(p)) => write!( + Expr::Call(fun, Some(p), _) => write!( f, "(Call {:width$?} with params {:?})", fun, p, width = width + 1 ), - Expr::Call(fun, _) => { + Expr::Call(fun, _, _) => { write!(f, "(Call {:width$?})", fun, width = width + 1) } - Expr::Op(l, o, r) => write!(f, "({:?} of {:?} and {:?})", o, l, r,), - Expr::Right(o, e) => write!( + Expr::Op(l, o, r, _) => { + write!(f, "({:?} of {:?} and {:?})", o, l, r,) + } + Expr::Right(o, e, _) => write!( f, "{tabs}({:width$?} of {:width$?})", o, @@ -144,7 +172,7 @@ impl fmt::Debug for Expr { tabs = tabs, width = width + 1 ), - Expr::Ternary(c, t, _f) => write!( + Expr::Ternary(c, t, _f, _) => write!( f, "{tabs}(If {:?} Then {:?} Else {:?})", c, @@ -198,6 +226,8 @@ impl fmt::Debug for Type { Type::Int => write!(f, "Int"), Type::Bool => write!(f, "Bool"), Type::Str => write!(f, "Str"), + Type::Void => write!(f, "Void"), + Type::Agg(type_of) => write!(f, "Agg({:?})", *type_of), } } } @@ -205,8 +235,10 @@ impl fmt::Debug for Type { impl fmt::Debug for Variable { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Variable::Single(i) => write!(f, "(Var {:?})", i), - Variable::Array(i, s) => write!(f, "(Arr {:?} at pos {:?})", i, s), + Variable::Single(i, _) => write!(f, "(Var {:?})", i), + Variable::Array(i, s, _) => { + write!(f, "(Arr {:?} at pos {:?})", i, s) + } } } } @@ -215,7 +247,7 @@ impl fmt::Debug for Decl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (width, tabs) = get_tabs(f); match self { - Decl::Single(i, t, Some(e)) => write!( + Decl::Single(i, t, Some(e), _) => write!( f, "{tabs}({:width$?} of type {:width$?} with value {:width$?})", i, @@ -225,7 +257,7 @@ impl fmt::Debug for Decl { width = width + 1 ), - Decl::Single(i, t, _) => write!( + Decl::Single(i, t, _, _) => write!( f, "{tabs}({:width$?} of type {:width$?})", i, @@ -234,7 +266,7 @@ impl fmt::Debug for Decl { width = width + 1 ), - Decl::Array(i, t, s, Some(e)) => write!( + Decl::Array(i, t, s, Some(e), _) => write!( f, "{tabs}([{:width$?}] of size {:width$?} of type {:width$?} with values {:width$?})", i, @@ -245,7 +277,7 @@ impl fmt::Debug for Decl { width = width + 1 ), - Decl::Array(i, t, s, _) => write!( + Decl::Array(i, t, s, _, _) => write!( f, "{tabs}([{:width$?}] of size {:width$?} of type {:width$?})", i, @@ -255,7 +287,7 @@ impl fmt::Debug for Decl { width = width + 1 ), - Decl::Func(i, Some(t), Some(p), b) => write!( + Decl::Func(i, Some(t), Some(p), b, _) => write!( f, "{tabs}(func {:?}\n {tabs}with params ({:?})\n {tabs}returning ({:width$?})\n {tabs}executing (\n{:width$?}\n {tabs}))", i, @@ -266,7 +298,7 @@ impl fmt::Debug for Decl { width = width + 3 ), - Decl::Func(i, Some(t), _, b) => write!( + Decl::Func(i, Some(t), _, b, _) => write!( f, "{tabs}(func {:?} with no params\n {tabs}returning ({:width$?})\n {tabs}executing (\n{:width$?})\n {tabs})", i, @@ -276,7 +308,7 @@ impl fmt::Debug for Decl { width = width + 3 ), - Decl::Func(i, _, Some(p), b) => write!( + Decl::Func(i, _, Some(p), b, _) => write!( f, "{tabs}(proc {:?}\n {tabs}with params ({:?})\n {tabs}executing (\n{:width$?})\n {tabs})", i, @@ -286,7 +318,7 @@ impl fmt::Debug for Decl { width = width + 3 ), - Decl::Func(i, _, _, b) => write!( + Decl::Func(i, _, _, b, _) => write!( f, "{tabs}(proc {:?} with no params executing (\n{:width$?})\n {tabs})", i, @@ -302,7 +334,7 @@ impl fmt::Debug for FuncParam { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (width, tabs) = get_tabs(f); match self { - FuncParam::Single(i, t) => write!( + FuncParam::Single(i, t, _) => write!( f, "{tabs}(Param {:width$?}, {:width$?})", i, @@ -310,7 +342,7 @@ impl fmt::Debug for FuncParam { tabs = tabs, width = width + 1 ), - FuncParam::Array(i, t) => write!( + FuncParam::Array(i, t, _) => write!( f, "{tabs}(Param {:width$?}[], {:width$?})", i, @@ -326,38 +358,38 @@ impl fmt::Debug for Stmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (width, tabs) = get_tabs(f); match self { - Stmt::Attr(v, e) => write!( + Stmt::Attr(v, e, _) => write!( f, "(Attr {:?} receives {:?})", v, e, ), - Stmt::Stop => write!(f, "Stop"), - Stmt::Skip => write!(f, "Skip"), + Stmt::Stop(_) => write!(f, "Stop"), + Stmt::Skip(_) => write!(f, "Skip"), - Stmt::Return(Some(a)) => { + Stmt::Return(Some(a), _) => { write!(f, "(Return {:?})", a) } - Stmt::Return(_) => write!(f, "Return"), + Stmt::Return(_, _) => write!(f, "Return"), - Stmt::Read(v) => write!(f, "(Read {:?})", v), - Stmt::Write(v) => write!(f, "(Write {:?})", v), + Stmt::Read(v, _) => write!(f, "(Read {:?})", v), + Stmt::Write(v, _) => write!(f, "(Write {:?})", v), - Stmt::Call(fun, Some(p)) => write!( + Stmt::Call(fun, Some(p), _) => write!( f, "(Call {:width$?} with params {:?})", fun, p, width = width + 1 ), - Stmt::Call(fun, _) => { + Stmt::Call(fun, _, _) => { write!(f, "(Call {:width$?})", fun, width = width + 1) } - Stmt::If(expr, b, _elif, _else) => { + Stmt::If(expr, b, _elif, _else, _) => { write!( f, "(If {:?} then (\n{:width$?})", expr, b, width = width + 1)?; - if _elif.len() == 0 { + if _elif.is_empty() { write!(f, " no elseifs")?; } else { write!(f, " elseifs [")?; @@ -374,7 +406,7 @@ impl fmt::Debug for Stmt { } }, - Stmt::While(e, b) => write!( + Stmt::While(e, b, _) => write!( f, "(While {:?} do(\n{:width$?}\n{tabs}))", e, @@ -382,7 +414,7 @@ impl fmt::Debug for Stmt { tabs = tabs, width = width + 1 ), - Stmt::For(i, t, s, b) => { + Stmt::For(i, t, s, b, _) => { write!( f, "(For\n {tabs}with init {:?}\n {tabs}and with test {:?}\n {tabs}and with step {:?}\n {tabs}then do(\n{:width$?}\n{tabs}))", @@ -423,7 +455,7 @@ impl fmt::Debug for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (width, tabs) = get_tabs(f); write!(f, "{tabs}(Block", tabs = tabs)?; - if self.decl.len() == 0 { + if self.decl.is_empty() { write!(f, "\n {tabs}with no decls", tabs = tabs)?; } else { write!(f, "\n {tabs}with decls [", tabs = tabs)?; @@ -438,7 +470,7 @@ impl fmt::Debug for Block { } write!(f, "\n {tabs}]", tabs = tabs)?; } - if self.commands.len() == 0 { + if self.commands.is_empty() { write!(f, " and with no commands\n{tabs})", tabs = tabs) } else { write!(f, " and with commands [")?; diff --git a/src/gen.rs b/src/gen.rs deleted file mode 100644 index 47e2241..0000000 --- a/src/gen.rs +++ /dev/null @@ -1,893 +0,0 @@ -use ast::*; -use llvm::{core::*, prelude::*}; - -use std::{ffi::*, ptr}; -use symbol_table::*; - -macro_rules! c_str { - ($s:expr) => {{ - concat!($s, "\0").as_ptr() as *const i8 - }}; -} - -macro_rules! m_str { - ($s:expr) => {{ - concat!($s, "\0").as_ptr() as *mut i8 - }}; -} - -macro_rules! mm_str { - ($s:expr) => {{ - concat!($s, "\0").as_ptr() as *mut *mut i8 - }}; -} - -macro_rules! as_str { - ($v:ident) => { - CString::new($v.clone()).unwrap().as_ptr() as *const i8 - }; -} - -unsafe fn gen_type(context: LLVMContextRef, t: Option) -> LLVMTypeRef { - match t { - Some(Type::Bool) => LLVMInt1TypeInContext(context), - Some(Type::Int) => LLVMInt64TypeInContext(context), - Some(Type::Str) => panic!("Do not use gen_type with Strings!"), - None => LLVMVoidTypeInContext(context), - } -} - -unsafe fn gen_array_type(context: LLVMContextRef, t: &Type) -> LLVMTypeRef { - match t { - Type::Bool => LLVMPointerType(LLVMInt1TypeInContext(context), 0), - Type::Int => LLVMPointerType(LLVMInt64TypeInContext(context), 0), - Type::Str => panic!("Do not use gen_array_type with Strings!"), - } -} - -unsafe fn flatten_expr( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &SymbolTable, - builder: LLVMBuilderRef, - e: Expr, -) -> LLVMValueRef { - let mut v = Vec::new(); - match e { - Expr::Number(n) => { - v.push(LLVMConstInt(gen_type(context, Some(Type::Int)), n, 1)); - } - Expr::Variable(Variable::Single(s)) => { - if let Ok(var) = symbols.get(&s) { - if let Symbol::Variable(mut var) = var { - let tmp = LLVMBuildLoad(builder, var, c_str!("flat")); - v.push(tmp); - } else { - panic!( - "Variable <{:?}> of a type diferent than expected!", - s - ); - } - } else { - panic!("Variable <{:?}> is used but not declared!", s); - } - } - Expr::Variable(Variable::Array(s, e)) => { - if let Ok(var) = symbols.get(&s) { - if let Symbol::ArrayRef(mut var) = var { - let index_flattened = - flatten_expr(context, module, symbols, builder, *e); - let loaded_array_ptr = - LLVMBuildLoad(builder, var, c_str!("loaded_param")); - let arr_at = LLVMBuildInBoundsGEP( - builder, - loaded_array_ptr, - [index_flattened].as_mut_ptr(), - 1, - c_str!("arr"), - ); - v.push(LLVMBuildLoad(builder, arr_at, c_str!("flat"))); - } else if let Symbol::Array(_, mut var) = var { - let flattened = - flatten_expr(context, module, symbols, builder, *e); - let arr_at = LLVMBuildGEP( - builder, - var, - [ - flattened, - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - ] - .as_mut_ptr(), - 2, - c_str!("arr"), - ); - v.push(LLVMBuildLoad(builder, arr_at, c_str!("flat"))); - } else { - panic!("Variable <{:?}> is used but not declared!", s); - } - } else { - panic!("Variable <{:?}> is used but not declared!", s); - } - } - Expr::True => { - v.push(LLVMConstInt(gen_type(context, Some(Type::Bool)), 1, 1)); - } - Expr::False => { - v.push(LLVMConstInt(gen_type(context, Some(Type::Bool)), 0, 1)); - } - Expr::Op(lhs, op, rhs) => match op { - Opcode::Add => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildAdd(builder, lhs, rhs, c_str!("add"))); - } - Opcode::Sub => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildSub(builder, lhs, rhs, c_str!("sub"))); - } - Opcode::Mul => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildMul(builder, lhs, rhs, c_str!("mul"))); - } - Opcode::Div => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildSDiv(builder, lhs, rhs, c_str!("sdiv"))); - } - Opcode::Mod => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildSRem(builder, lhs, rhs, c_str!("srem"))); - } - Opcode::Lesser - | Opcode::LesserOrEqual - | Opcode::Greater - | Opcode::GreaterOrEqual - | Opcode::Equal - | Opcode::Different => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildICmp( - builder, - op.pred(), - lhs, - rhs, - c_str!("cmp"), - )); - } - Opcode::And => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildAnd(builder, lhs, rhs, c_str!("and"))); - } - Opcode::Or => { - let lhs = flatten_expr(context, module, symbols, builder, *lhs); - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildOr(builder, lhs, rhs, c_str!("or"))); - } - _ => panic!("IMPOSSIBURU! Opcode<{:?}> is unary!", op), - }, - Expr::Call(n, None) => { - let called_fn = LLVMGetNamedFunction(module, as_str!(n)); - v.push(LLVMBuildCall( - builder, - called_fn, - [].as_mut_ptr(), - 0, - c_str!("fn_call"), - )); - } - Expr::Right(Opcode::Negative, rhs) => { - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildMul( - builder, - LLVMConstInt( - gen_type(context, Some(Type::Int)), - -1i64 as u64, - 1, - ), - rhs, - c_str!("neg"), - )); - } - Expr::Right(Opcode::Not, rhs) => { - let rhs = flatten_expr(context, module, symbols, builder, *rhs); - v.push(LLVMBuildNot(builder, rhs, c_str!("not"))); - } - Expr::Right(o, _) => { - panic!("IMPOSSIBURU! Opcode<{:?}> is binary!", o); - } - _ => println!("uninplemented!"), - } - if let Some(a) = v.last().cloned() { - a - } else { - //panic!("invalid state"); - LLVMConstInt(gen_type(context, Some(Type::Int)), 42, 1) - } -} - -unsafe fn local_add_variable( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - builder: LLVMBuilderRef, - n: &str, - t: Type, - e: Option>, -) { - let t = gen_type(context, Some(t)); - let decl = LLVMBuildAlloca(builder, t, as_str!(n)); - if let Some(e) = e { - let flattened = flatten_expr(context, module, symbols, builder, *e); - LLVMBuildStore(builder, flattened, decl); - } else { - LLVMBuildStore(builder, LLVMConstInt(t, 0, 1), decl); - } - let new_symbol = Symbol::Variable(decl); - symbols.set(&n, new_symbol); -} - -unsafe fn local_add_array( - context: LLVMContextRef, - symbols: &mut SymbolTable, - builder: LLVMBuilderRef, - n: &str, - t: Type, - s: u64, - e: Option>>, -) { - let t = gen_type(context, Some(t)); - let array_type = LLVMArrayType(t, s as u32); - let decl = LLVMBuildArrayAlloca( - builder, - array_type, - LLVMConstInt(t, 0, 1), - as_str!(n), - ); - if let Some(e) = e { - for (i, e) in e.iter().enumerate() { - match **e { - Expr::Number(e) => { - let ptr = LLVMBuildGEP( - builder, - decl, - [ - LLVMConstInt( - gen_type(context, Some(Type::Int)), - i as u64, - 1, - ), - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - ] - .as_mut_ptr(), - 2, - c_str!("ptr_get"), - ); - LLVMBuildStore(builder, LLVMConstInt(t, e, 1), ptr); - } - Expr::True => { - let ptr = LLVMBuildGEP( - builder, - decl, - [ - LLVMConstInt( - gen_type(context, Some(Type::Int)), - i as u64, - 1, - ), - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - ] - .as_mut_ptr(), - 2, - c_str!("ptr_get"), - ); - LLVMBuildStore(builder, LLVMConstInt(t, 1, 1), ptr); - } - Expr::False => { - let ptr = LLVMBuildGEP( - builder, - decl, - [ - LLVMConstInt( - gen_type(context, Some(Type::Int)), - i as u64, - 1, - ), - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - ] - .as_mut_ptr(), - 2, - c_str!("ptr_get"), - ); - LLVMBuildStore(builder, LLVMConstInt(t, 0, 1), ptr); - } - _ => panic!( - "Cannot initialize global value with non-const expresion!" - ), - }; - } - /* - *let mut args = e - * .iter() - * .map(|b| match **b { - * Expr::Number(e) => LLVMConstInt(t, e, 1), - * Expr::True => LLVMConstInt(t, 1, 1), - * Expr::False => LLVMConstInt(t, 0, 1), - * _ => panic!("Cannot initialize global value with non-const expresion!"), - * }) - * .collect::>(); - *let values = LLVMConstArray(t, args.as_mut_ptr(), args.len() as u32); - *LLVMBuildStore(builder, values, decl); - */ - } - let new_symbol = Symbol::Array(s as u32, decl); - - symbols.set(&n, new_symbol); -} - -unsafe fn global_add_func( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - n: &str, - t: Option, // Return Type - a: Option>, - b: Block, -) { - let builder = LLVMCreateBuilderInContext(context); - let t = gen_type(context, t); - let args = if let Some(a) = a { - a.iter() - .map(|p| match p { - FuncParam::Single(n, t) => { - (n.clone(), true, gen_type(context, Some(t.clone()))) - } - FuncParam::Array(n, t) => { - (n.clone(), false, gen_array_type(context, &t.clone())) - } - }) - .collect::>() - } else { - Vec::new() - }; - let function_type = LLVMFunctionType( - t, - args.iter().map(|a| a.2).collect::>().as_mut_ptr(), - args.len() as u32, - 0, - ); - let function = LLVMAddFunction(module, as_str!(n), function_type); - - symbols.initialize_scope(); - - let entry = - LLVMAppendBasicBlockInContext(context, function, c_str!("entry")); - LLVMPositionBuilderAtEnd(builder, entry); - - for (i, e) in args.iter().enumerate() { - if e.1 { - let fn_param = LLVMGetParam(function, i as u32); - let alloced_param = LLVMBuildAlloca(builder, e.2, c_str!("param")); - LLVMBuildStore(builder, fn_param, alloced_param); - let new_symbol = Symbol::Variable(alloced_param); - symbols.set(&e.0, new_symbol); - } else { - let fn_param = LLVMGetParam(function, i as u32); - let alloced_param = LLVMBuildAlloca(builder, e.2, c_str!("param")); - LLVMBuildStore(builder, fn_param, alloced_param); - let new_symbol = Symbol::ArrayRef(alloced_param); - symbols.set(&e.0, new_symbol); - } - } - - let test = LLVMGetNamedFunction(module, c_str!("printf")); - // Stupid way of checking if the function is already defined. - let against = ptr::null::() as *mut _; - if test == against { - LLVMBuildGlobalStringPtr(builder, c_str!("%d"), c_str!("format_int")); - LLVMBuildGlobalStringPtr(builder, c_str!("%s"), c_str!("format_str")); - - let int8_type = LLVMInt8TypeInContext(context); - let int32_type = LLVMInt32TypeInContext(context); - let mut args = [LLVMPointerType(int8_type, 0)]; - let fn_type = LLVMFunctionType(int32_type, args.as_mut_ptr(), 0, 1); - - LLVMAddFunction(module, c_str!("printf"), fn_type); - LLVMAddFunction(module, c_str!("scanf"), fn_type); - } - - gen_decl(context, module, symbols, builder, b.decl, false); - gen_block( - context, module, symbols, builder, function, None, b.commands, - ); - - symbols.kill_scope(); - - LLVMDisposeBuilder(builder); - let new_symbol = Symbol::Func(n.to_string()); - - symbols.set(&n, new_symbol); -} - -unsafe fn gen_decl( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - builder: LLVMBuilderRef, - decl: Vec, - allow_fn: bool, -) { - for i in decl { - match i { - Decl::Single(n, t, e) => { - local_add_variable(context, module, symbols, builder, &n, t, e) - } - Decl::Array(n, t, s, e) => { - local_add_array(context, symbols, builder, &n, t, s, e) - } - Decl::Func(_, _, _, _) => { - if allow_fn { - println!("unimplemented"); - } else { - panic!("Functions are not allowed here!"); - } - } - } - } -} - -unsafe fn build_attr( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &SymbolTable, - builder: LLVMBuilderRef, - v: &str, - e: Expr, -) -> Result<(), String> { - if let Ok(var) = symbols.get(&v) { - if let Symbol::Variable(mut var) = var { - let flattened = flatten_expr(context, module, symbols, builder, e); - LLVMBuildStore(builder, flattened, var); - Ok(()) - } else { - Err(format!("Variable <{:?}> is used but not declared!", v)) - } - } else { - Err(format!("Variable <{:?}> is used but not declared!", v)) - } -} - -unsafe fn gen_block( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - builder: LLVMBuilderRef, - parent: LLVMValueRef, - looping: Option<(LLVMBasicBlockRef, LLVMBasicBlockRef)>, - stmts: Vec>, -) { - symbols.initialize_scope(); - - for i in stmts { - match i { - Either::Left(Stmt::Attr(Variable::Single(v), e)) => { - if let Err(s) = - build_attr(context, module, symbols, builder, &v, *e) - { - panic!(s); - } - } - Either::Left(Stmt::Write(vec)) => { - for i in vec { - let flattened = - flatten_expr(context, module, symbols, builder, *i); - let format_str = - LLVMGetNamedGlobal(module, c_str!("format_int")); - let mut printf_args = [format_str, flattened]; - let printf_fn = - LLVMGetNamedFunction(module, c_str!("printf")); - LLVMBuildCall( - builder, - printf_fn, - printf_args.as_mut_ptr(), - 2, - c_str!("write"), - ); - } - } - Either::Left(Stmt::Read(Variable::Single(v))) => { - if let Ok(var) = symbols.get(&v) { - if let Symbol::Variable(mut var) = var { - let format_str = - LLVMGetNamedGlobal(module, c_str!("format_int")); - let mut scanf_args = [format_str, var]; - let scanf_fn = - LLVMGetNamedFunction(module, c_str!("scanf")); - LLVMBuildCall( - builder, - scanf_fn, - scanf_args.as_mut_ptr(), - 2, - c_str!("read"), - ); - } - } - } - Either::Left(Stmt::Read(Variable::Array(v, e))) => { - if let Ok(var) = symbols.get(&v) { - if let Symbol::ArrayRef(mut var) = var { - let flattened = - flatten_expr(context, module, symbols, builder, *e); - let arr_at = LLVMBuildGEP( - builder, - var, - [ - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - flattened, - ] - .as_mut_ptr(), - 2, - c_str!("arr"), - ); - let format_str = - LLVMGetNamedGlobal(module, c_str!("format_int")); - let mut scanf_args = [format_str, arr_at]; - let scanf_fn = - LLVMGetNamedFunction(module, c_str!("scanf")); - LLVMBuildCall( - builder, - scanf_fn, - scanf_args.as_mut_ptr(), - 2, - c_str!("read"), - ); - } else if let Symbol::Array(_, mut var) = var { - let flattened = - flatten_expr(context, module, symbols, builder, *e); - let arr_at = LLVMBuildGEP( - builder, - var, - [ - LLVMConstInt( - gen_type(context, Some(Type::Int)), - 0, - 1, - ), - flattened, - ] - .as_mut_ptr(), - 2, - c_str!("arr"), - ); - let format_str = - LLVMGetNamedGlobal(module, c_str!("format_int")); - let mut scanf_args = [format_str, arr_at]; - let scanf_fn = - LLVMGetNamedFunction(module, c_str!("scanf")); - LLVMBuildCall( - builder, - scanf_fn, - scanf_args.as_mut_ptr(), - 2, - c_str!("read"), - ); - } - } - } - Either::Left(Stmt::Call(n, None)) => { - let called_fn = LLVMGetNamedFunction(module, as_str!(n)); - LLVMBuildCall( - builder, - called_fn, - [].as_mut_ptr(), - 0, - c_str!(""), - ); - } - Either::Left(Stmt::Skip) => { - if let Some((skip, _)) = looping { - LLVMBuildBr(builder, skip); - } else { - panic!("cannot use skip outside of a loop"); - } - } - Either::Left(Stmt::Stop) => { - if let Some((_, stop)) = looping { - LLVMBuildBr(builder, stop); - } else { - panic!("cannot use skip outside of a loop"); - } - } - Either::Left(Stmt::Return(v)) => { - if let Some(v) = v { - let flattened = - flatten_expr(context, module, symbols, builder, *v); - LLVMBuildRet(builder, flattened); - } else { - LLVMBuildRetVoid(builder); - } - } - Either::Left(Stmt::If(cond, then, else_ifs, None)) => { - let then_block = LLVMAppendBasicBlock(parent, c_str!("then")); - let merge = LLVMAppendBasicBlock(parent, c_str!("merge")); - - let cond = - flatten_expr(context, module, symbols, builder, *cond); - LLVMBuildCondBr(builder, cond, then_block, merge); - - // Build True Branch - LLVMPositionBuilderAtEnd(builder, then_block); - gen_decl(context, module, symbols, builder, then.decl, false); - gen_block( - context, - module, - symbols, - builder, - parent, - looping, - then.commands, - ); - LLVMBuildBr(builder, merge); - - // Build Merge Branch - LLVMPositionBuilderAtEnd(builder, merge); - } - Either::Left(Stmt::If(cond, then, else_ifs, Some(_else))) => { - let then_block = LLVMAppendBasicBlock(parent, c_str!("then")); - let else_block = LLVMAppendBasicBlock(parent, c_str!("else")); - let merge = LLVMAppendBasicBlock(parent, c_str!("merge")); - - let cond = - flatten_expr(context, module, symbols, builder, *cond); - LLVMBuildCondBr(builder, cond, then_block, else_block); - - // Build True Branch - LLVMPositionBuilderAtEnd(builder, then_block); - gen_decl(context, module, symbols, builder, then.decl, false); - gen_block( - context, - module, - symbols, - builder, - parent, - looping, - then.commands, - ); - LLVMBuildBr(builder, merge); - - // Build False Branch - LLVMPositionBuilderAtEnd(builder, else_block); - gen_decl(context, module, symbols, builder, _else.decl, false); - gen_block( - context, - module, - symbols, - builder, - parent, - looping, - _else.commands, - ); - LLVMBuildBr(builder, merge); - - // Build Merge Branch - LLVMPositionBuilderAtEnd(builder, merge); - } - Either::Left(Stmt::For(init, cond, step, block)) => { - let cond_block = - LLVMAppendBasicBlock(parent, c_str!("cond_loop")); - let loop_block = LLVMAppendBasicBlock(parent, c_str!("loop")); - let step_block = LLVMAppendBasicBlock(parent, c_str!("step")); - let exit_block = - LLVMAppendBasicBlock(parent, c_str!("exit_loop")); - - let init = *init; - // Build attribution before entering init_block - if let Stmt::Attr(Variable::Single(v), e) = init { - if let Err(s) = - build_attr(context, module, symbols, builder, &v, *e) - { - panic!(s); - } - } else if let Stmt::Attr(Variable::Array(v, i), e) = init { - println!("uninplemented!"); - } else { - panic!("invalid state"); - } - LLVMBuildBr(builder, cond_block); - - // Build condition inside cond_block - LLVMPositionBuilderAtEnd(builder, cond_block); - let cond = - flatten_expr(context, module, symbols, builder, *cond); - LLVMBuildCondBr(builder, cond, loop_block, exit_block); - - // Position at loop to build loop's instructions - LLVMPositionBuilderAtEnd(builder, loop_block); - gen_decl(context, module, symbols, builder, block.decl, false); - gen_block( - context, - module, - symbols, - builder, - parent, - Some((step_block, exit_block)), - block.commands, - ); - LLVMBuildBr(builder, step_block); - - LLVMPositionBuilderAtEnd(builder, step_block); - // Add step to end of loop block - let step = *step; - if let Stmt::Attr(Variable::Single(v), e) = step { - if let Err(s) = - build_attr(context, module, symbols, builder, &v, *e) - { - panic!(s); - } - } else if let Stmt::Attr(Variable::Array(v, i), e) = step { - println!("uninplemented!"); - } else { - panic!("invalid state"); - } - LLVMBuildBr(builder, cond_block); - - // Continue at exit_loop - LLVMPositionBuilderAtEnd(builder, exit_block); - } - - Either::Left(Stmt::While(cond, block)) => { - let cond_block = - LLVMAppendBasicBlock(parent, c_str!("cond_loop")); - let loop_block = LLVMAppendBasicBlock(parent, c_str!("loop")); - let exit_block = - LLVMAppendBasicBlock(parent, c_str!("exit_loop")); - - LLVMBuildBr(builder, cond_block); - - LLVMPositionBuilderAtEnd(builder, cond_block); - // Build condition inside cond_block - let cond = - flatten_expr(context, module, symbols, builder, *cond); - LLVMBuildCondBr(builder, cond, loop_block, exit_block); - - // Position at loop to build loop's instructions - LLVMPositionBuilderAtEnd(builder, loop_block); - gen_decl(context, module, symbols, builder, block.decl, false); - gen_block( - context, - module, - symbols, - builder, - parent, - Some((cond_block, exit_block)), - block.commands, - ); - LLVMBuildBr(builder, cond_block); - - // Continue at exit_loop - LLVMPositionBuilderAtEnd(builder, exit_block); - } - - Either::Left(_) => println!("uninplemented!"), - Either::Right(b) => { - for i in b.decl { - match i { - Decl::Single(n, t, e) => local_add_variable( - context, module, symbols, builder, &n, t, e, - ), - Decl::Array(n, t, s, e) => local_add_array( - context, symbols, builder, &n, t, s, e, - ), - _ => { - panic!("Cannot declare functions inside functions!") - } - } - } - gen_block( - context, module, symbols, builder, parent, looping, - b.commands, - ) - } - } - } - - symbols.kill_scope(); -} - -unsafe fn global_add_variable( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - n: &str, - t: Type, - e: Option>, -) { - let t = gen_type(context, Some(t)); - let decl = LLVMAddGlobal(module, t, as_str!(n)); - if let Some(e) = e { - let b = *e; - if let Expr::Number(v) = b { - LLVMSetInitializer(decl, LLVMConstInt(t, v as u64, 1)); - } - } else { - panic!("Cannot initialize global value with non-const expresion!"); - } - let new_symbol = Symbol::Variable(decl); - symbols.set(&n, new_symbol); -} - -unsafe fn global_add_array( - context: LLVMContextRef, - module: LLVMModuleRef, - symbols: &mut SymbolTable, - n: &str, - t: Type, - s: u64, - e: Option>>, -) { - let t = gen_type(context, Some(t)); - let array_type = LLVMArrayType(t, s as u32); - let decl = LLVMAddGlobal(module, array_type, as_str!(n)); - if let Some(e) = e { - let mut args = e - .iter() - .map(|b| match **b { - Expr::Number(e) => LLVMConstInt(t, e, 1), - Expr::True => LLVMConstInt(t, 1, 1), - Expr::False => LLVMConstInt(t, 0, 1), - _ => panic!( - "Cannot initialize global value with non-const expresion!" - ), - }) - .collect::>(); - let values = LLVMConstArray(t, args.as_mut_ptr(), args.len() as u32); - LLVMSetInitializer(decl, values); - } - let new_symbol = Symbol::Array(s as u32, decl); - symbols.set(&n, new_symbol); -} - -pub unsafe fn gen(decls: Vec) { - let context = LLVMContextCreate(); - let module = LLVMModuleCreateWithNameInContext(c_str!("program"), context); - let mut symbols = SymbolTable::new(); - for i in decls { - match i { - Decl::Single(n, t, e) => { - global_add_variable(context, module, &mut symbols, &n, t, e) - } - Decl::Array(n, t, s, e) => { - global_add_array(context, module, &mut symbols, &n, t, s, e) - } - Decl::Func(n, t, a, b) => { - global_add_func(context, module, &mut symbols, &n, t, a, b) - } - } - } - LLVMDumpModule(module); - LLVMPrintModuleToFile(module, c_str!("test.ll"), mm_str!("idk")); - LLVMContextDispose(context); -} diff --git a/src/gen/context.rs b/src/gen/context.rs new file mode 100644 index 0000000..8879c19 --- /dev/null +++ b/src/gen/context.rs @@ -0,0 +1,51 @@ +use super::{ + super::ast::Type, + symbol_table::{Symbol, SymbolTable}, +}; +use llvm::{core::*, *}; +use std::ffi::CString; + +#[derive(Clone)] +pub struct Context { + pub symbol_table: SymbolTable, + pub module: *mut LLVMModule, + pub context: *mut LLVMContext, + pub builder: *mut LLVMBuilder, + pub current_function: Option<(*mut LLVMValue, *mut LLVMBasicBlock)>, // (function, entry) +} + +impl Context { + pub unsafe fn new() -> Context { + let context = LLVMContextCreate(); + + Context { + symbol_table: SymbolTable::new(), + module: LLVMModuleCreateWithName(as_str!("program")), + context, + current_function: None, + builder: LLVMCreateBuilderInContext(context), + } + } + + pub unsafe fn declare_printf_scanf(self: &mut Self) { + let int8_type = LLVMInt8TypeInContext(self.context); + let int32_type = LLVMInt32TypeInContext(self.context); + let mut args = [LLVMPointerType(int8_type, 0)]; + let fn_type = LLVMFunctionType(int32_type, args.as_mut_ptr(), 1, 1); + + let printf_fn = + LLVMAddFunction(self.module, as_str!("printf"), fn_type); + let scanf_fn = LLVMAddFunction(self.module, as_str!("scanf"), fn_type); + + self.symbol_table + .set( + "0printf", + Symbol::Func(printf_fn, (Type::Int, vec![Type::Str])), + ) + .unwrap(); + + self.symbol_table + .set("0scanf", Symbol::Func(scanf_fn, (Type::Int, vec![]))) + .unwrap(); + } +} diff --git a/src/gen/emit.rs b/src/gen/emit.rs new file mode 100644 index 0000000..c861d41 --- /dev/null +++ b/src/gen/emit.rs @@ -0,0 +1,1242 @@ +use super::{super::ast::*, context::*, symbol_table::*}; +use llvm::{core::*, *}; +use std::ffi::CString; + +pub type SemanticError = (String, Location); + +pub trait Emit { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result; +} + +impl Emit<*mut LLVMType> for Type { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<*mut LLVMType, SemanticError> { + match self { + Type::Int => Ok(LLVMInt64TypeInContext(context.context)), + Type::Bool => Ok(LLVMInt1TypeInContext(context.context)), + Type::Void => Ok(LLVMVoidTypeInContext(context.context)), + Type::Str => panic!("Not implemented"), + Type::Agg(type_of) => { + Ok(LLVMPointerType(type_of.emit(context)?, 0)) + } + } + } +} + +impl Emit<(*mut LLVMValue, Type)> for Variable { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(*mut LLVMValue, Type), SemanticError> { + let builder = context.builder; + match self { + Variable::Single(identifier, location) => { + if let Ok(value) = context.symbol_table.get(identifier) { + match value { + Symbol::Variable(value, type_of) + | Symbol::Array(value, type_of) => { + Ok((*value, type_of.clone())) + } + _ => Err(( + format!("Variable {} type mismatch", identifier), + *location, + )), + } + } else { + Err(("variabe not declared".to_string(), *location)) + } + } + Variable::Array(identifier, expression, location) => { + if let Ok(value) = context.clone().symbol_table.get(identifier) + { + let (index, type_of_index) = expression.emit(context)?; + if type_of_index != Type::Int { + return Err(( + "array index must be an integer".to_string(), + *location, + )); + } + + match value { + Symbol::Array(value, type_of) => Ok(( + LLVMBuildInBoundsGEP( + builder, + *value, + [index].as_mut_ptr(), + 1, + as_str!("ptr_value"), + ), + type_of.clone(), + )), + _ => Err(( + format!("Variable {} type mismatch", identifier), + *location, + )), + } + } else { + Err(( + format!("Variable {} not defined", identifier), + *location, + )) + } + } + } + } +} + +impl Emit<(*mut LLVMValue, Type)> for Expr { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(*mut LLVMValue, Type), (String, Location)> { + match self { + Expr::Number(number, _location) => Ok(( + LLVMConstInt(Type::Int.emit(context)?, *number, 1), + Type::Int, + )), + Expr::StringLitteral(string, _location) => Ok(( + LLVMBuildGlobalStringPtr( + context.builder, + as_str!(string), + as_str!("string"), + ), + Type::Str, + )), + Expr::True(_location) => { + Ok((LLVMConstInt(Type::Bool.emit(context)?, 1, 1), Type::Bool)) + } + Expr::False(_location) => { + Ok((LLVMConstInt(Type::Bool.emit(context)?, 0, 1), Type::Bool)) + } + Expr::Variable(var, _location) => { + let (ptr_var, type_of) = var.emit(context)?; + + match type_of { + Type::Str => Ok((ptr_var, type_of)), + _ => Ok(( + LLVMBuildLoad( + context.builder, + ptr_var, + as_str!("var_load"), + ), + type_of, + )), + } + } + Expr::Call(identifier, params, location) => { + let builder = context.builder; + if let Ok(function) = + context.clone().symbol_table.get(identifier) + { + match function { + // TODO Put function value in symbols table + Symbol::Func(function, function_signature) => { + let params = params.clone().unwrap_or_default(); + let function_signature = function_signature.clone(); + + let mut name = if function_signature.0 == Type::Void + { + "".to_string() + } else { + "call".to_string() + }; + + Ok(( + LLVMBuildCall( + builder, + *function, + params + .iter() + .zip(function_signature.1) + .map::, _>(|(param, param_expected_type)| { + let (value, type_of) = param.emit(context)?; + if type_of == param_expected_type { + Err(("Tipo do parametro diferente do esperado".to_string(), *location)) + } + else { Ok(value) } + }) + .collect::, _>>()? + .as_mut_ptr(), + params.len() as u32, + as_str!(name), + ), + function_signature.0, + )) + } + _ => Err(("Type mismatch".to_string(), *location)), + } + } else { + Err(("Identifier not declared".to_string(), *location)) + } + } + Expr::Op(lhs, op, rhs, location) => { + let builder = context.builder; + let (lhs, type_of_lhs) = lhs.emit(context)?; + let (rhs, type_of_rhs) = rhs.emit(context)?; + let mut type_of_result; + let value = match op { + Opcode::Add => { + if type_of_lhs != Type::Int { + return Err(( + "Lado esquerda da soma não é inteiro" + .to_string(), + *location, + )); + } + if type_of_rhs != Type::Int { + return Err(( + "Lado direito da soma não é inteiro" + .to_string(), + *location, + )); + } + type_of_result = Type::Int; + LLVMBuildAdd(builder, lhs, rhs, as_str!("add_result")) + } + Opcode::Sub => { + if type_of_lhs != Type::Int { + return Err(( + "Lado esquerda da subtração não é inteiro" + .to_string(), + *location, + )); + } + if type_of_rhs != Type::Int { + return Err(( + "Lado direito da subtração não é inteiro" + .to_string(), + *location, + )); + } + type_of_result = Type::Int; + LLVMBuildSub(builder, lhs, rhs, as_str!("sub_result")) + } + Opcode::Div => { + if type_of_lhs != Type::Int { + return Err(( + "Lado esquerda da divisão não é inteiro" + .to_string(), + *location, + )); + } + if type_of_rhs != Type::Int { + return Err(( + "Lado direito da divisão não é inteiro" + .to_string(), + *location, + )); + } + type_of_result = Type::Int; + + LLVMBuildUDiv(builder, lhs, rhs, as_str!("div_result")) + } + Opcode::Mul => { + if type_of_lhs != Type::Int { + return Err(("Lado esquerda da multiplicação não é inteiro".to_string(), *location)); + } + if type_of_rhs != Type::Int { + return Err(("Lado direito da multiplicação não é inteiro".to_string(), *location)); + } + type_of_result = Type::Int; + + LLVMBuildMul(builder, lhs, rhs, as_str!("mul_result")) + } + Opcode::And => { + if type_of_lhs != Type::Bool { + return Err(("Lado esquerda da multiplicação não é booleano".to_string(), *location)); + } + if type_of_rhs != Type::Bool { + return Err(("Lado direito da multiplicação não é booleano".to_string(), *location)); + } + type_of_result = Type::Bool; + + LLVMBuildAnd(builder, lhs, rhs, as_str!("and_result")) + } + Opcode::Or => { + if type_of_lhs != Type::Bool { + return Err(("Lado esquerda da multiplicação não é booleano".to_string(), *location)); + } + if type_of_rhs != Type::Bool { + return Err(("Lado direito da multiplicação não é booleano".to_string(), *location)); + } + type_of_result = Type::Bool; + + LLVMBuildOr(builder, lhs, rhs, as_str!("or_result")) + } + Opcode::Mod => { + if type_of_lhs != Type::Int { + return Err(( + "Lado esquerda do modulo não é inteiro" + .to_string(), + *location, + )); + } + if type_of_rhs != Type::Int { + return Err(( + "Lado direito do modulo não é inteiro" + .to_string(), + *location, + )); + } + type_of_result = Type::Int; + + LLVMBuildURem(builder, lhs, rhs, as_str!("mod_result")) + } + Opcode::Lesser + | Opcode::LesserOrEqual + | Opcode::Greater + | Opcode::GreaterOrEqual + | Opcode::Equal + | Opcode::Different => { + if type_of_lhs != type_of_rhs { + return Err(( + "Lado esquerda da comparação não é do mesmo tipo que o direito" + .to_string(), + *location, + )); + } + type_of_result = Type::Bool; + LLVMBuildICmp( + context.builder, + op.pred(), + lhs, + rhs, + as_str!("cmp"), + ) + } + _ => panic!("Not implemented"), + }; + Ok((value, type_of_result)) // FIXME type_of depend on the operand + } + Expr::Right(op, expression, location) => { + let builder = context.builder; + let (expression, type_of) = expression.emit(context)?; + match op { + Opcode::Not => { + if type_of == Type::Bool { + Ok(( + LLVMBuildNot( + builder, + expression, + as_str!("not_result"), + ), + Type::Bool, + )) + } else { + Err(("Should be a boolean".to_string(), *location)) + } + } + Opcode::Negative => { + if type_of == Type::Int { + Ok(( + LLVMBuildNeg( + builder, + expression, + as_str!("negation_result"), + ), + Type::Int, + )) + } else { + Err(("Should be an integer".to_string(), *location)) + } + } + _ => Err(("Should not reach this".to_string(), *location)), + } + } + Expr::Ternary(predicate, truehs, falsehs, location) => { + let builder = context.builder; + + let block_predicate = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("ternary_predicate"), + ); + LLVMBuildBr(context.builder, block_predicate); + let block_truehs = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("ternary_truehs"), + ); + let block_falsehs = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("ternary_falsehs"), + ); + let block_merge = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("ternary_merge"), + ); + + LLVMPositionBuilderAtEnd(context.builder, block_predicate); + let (predicate, type_of_predicate) = predicate.emit(context)?; + if type_of_predicate != Type::Bool { + return Err(( + "Predicado do ternário não é do tipo booleano" + .to_string(), + *location, + )); + } + LLVMBuildCondBr( + context.builder, + predicate, + block_truehs, + block_falsehs, + ); + + LLVMPositionBuilderAtEnd(context.builder, block_truehs); + let (truehs, type_of_truehs) = truehs.emit(context)?; + LLVMBuildBr(context.builder, block_merge); + + LLVMPositionBuilderAtEnd(context.builder, block_falsehs); + let (falsehs, type_of_falsehs) = falsehs.emit(context)?; + LLVMBuildBr(context.builder, block_merge); + + if type_of_truehs != type_of_falsehs { + return Err(( + "Caso positivo do ternario não é do mesmo tipo do caso negativo" + .to_string(), + *location, + )); + } + + LLVMPositionBuilderAtEnd(context.builder, block_merge); + let phi = LLVMBuildPhi( + builder, + type_of_truehs.emit(context)?, + as_str!("phi_result"), + ); + LLVMAddIncoming( + phi, + [truehs, falsehs].as_mut_ptr(), + [block_truehs, block_falsehs].as_mut_ptr(), + 2, + ); + + Ok((phi, type_of_truehs)) + } + } + } +} + +impl Emit<()> for Stmt { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(), (String, Location)> { + let builder = context.builder; + match self { + Stmt::Attr(var, expression, location) => { + let (ptr_var, type_of) = var.emit(context)?; + let (expression, type_of_expression) = + expression.emit(context)?; + if type_of_expression != type_of { + return Err(( + "Atribuição inválida".to_string(), + *location, + )); + } + + LLVMBuildStore(builder, expression, ptr_var); + Ok(()) + } + Stmt::Call(identifier, expressions, location) => { + Expr::Call( + identifier.to_string(), + expressions.clone(), + *location, + ) + .emit(context)?; + Ok(()) + } + Stmt::For(init, predicate, step, block, location) => { + init.emit(context)?; + let block_predicate = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("predicate_for"), + ); + let block_for = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("block_for"), + ); + let block_step = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("block_step"), + ); + let block_merge = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("merge_for"), + ); + + context.symbol_table.initialize_scope(); + context + .symbol_table + .set("0loop_merge", Symbol::JumpBlock(block_merge)) + .unwrap(); + context + .symbol_table + .set("0loop_step", Symbol::JumpBlock(block_step)) + .unwrap(); + + LLVMBuildBr(context.builder, block_predicate); + + LLVMPositionBuilderAtEnd(context.builder, block_predicate); + let (predicate, type_of_predicate) = predicate.emit(context)?; + if type_of_predicate != Type::Bool { + return Err(( + "Predicado não é booleano".to_string(), + *location, + )); + } + LLVMBuildCondBr( + context.builder, + predicate, + block_for, + block_merge, + ); + + LLVMPositionBuilderAtEnd(context.builder, block_for); + block.emit(context)?; + LLVMBuildBr(context.builder, block_step); + LLVMPositionBuilderAtEnd(context.builder, block_step); + step.emit(context)?; + LLVMBuildBr(context.builder, block_predicate); + context.symbol_table.kill_scope(); + + LLVMPositionBuilderAtEnd(context.builder, block_merge); + + Ok(()) + } + Stmt::While(predicate, block, location) => { + let block_predicate = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("predicate_for"), + ); + let block_while = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("block_for"), + ); + let block_merge = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("merge_for"), + ); + + context.symbol_table.initialize_scope(); + context + .symbol_table + .set("0loop_merge", Symbol::JumpBlock(block_merge)) + .unwrap(); + context + .symbol_table + .set("0loop_step", Symbol::JumpBlock(block_predicate)) + .unwrap(); + + LLVMBuildBr(context.builder, block_predicate); + + LLVMPositionBuilderAtEnd(context.builder, block_predicate); + let (predicate, type_of_predicate) = predicate.emit(context)?; + + if type_of_predicate != Type::Bool { + return Err(( + "Predicado não é booleano".to_string(), + *location, + )); + } + LLVMBuildCondBr( + context.builder, + predicate, + block_while, + block_merge, + ); + + LLVMPositionBuilderAtEnd(context.builder, block_while); + block.emit(context)?; + LLVMBuildBr(context.builder, block_predicate); + context.symbol_table.kill_scope(); + + LLVMPositionBuilderAtEnd(context.builder, block_merge); + + Ok(()) + } + Stmt::Stop(location) => { + if let Ok(merge) = context.symbol_table.get("0loop_merge") { + if let Symbol::JumpBlock(merge) = merge { + LLVMBuildBr(context.builder, *merge); + Ok(()) + } else { + Err(("Impossibru!!".to_string(), *location)) + } + } else { + Err(("Stop not in a loop".to_string(), *location)) + } + } + Stmt::Skip(location) => { + if let Ok(predicate) = context.symbol_table.get("0loop_step") { + if let Symbol::JumpBlock(predicate) = predicate { + LLVMBuildBr(context.builder, *predicate); + Ok(()) + } else { + Err(("Impossibru!!".to_string(), *location)) + } + } else { + Err(("Skip not in a loop".to_string(), *location)) + } + } + Stmt::Return(expression, _location) => { + // TODO Check return expression type match function return type + if let Some(expression) = expression { + let (expression, _type_of) = + expression.emit(context).unwrap(); + LLVMBuildRet(context.builder, expression); + Ok(()) + } else { + LLVMBuildRetVoid(context.builder); + Ok(()) + } + } + Stmt::If(expression, block, elifs, else_block, location) => { + let block_if_predicate = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("if_predicate"), + ); + LLVMBuildBr(context.builder, block_if_predicate); + let block_if_then = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("if_then"), + ); + let block_merge = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("merge_if"), + ); + let last_block = match else_block { + Some(else_block) => { + let block_if_else = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("if_else"), + ); + LLVMPositionBuilderAtEnd( + context.builder, + block_if_else, + ); + context.symbol_table.initialize_scope(); + else_block.emit(context).unwrap(); + context.symbol_table.kill_scope(); + LLVMBuildBr(context.builder, block_merge); + + block_if_else + } + None => block_merge, + }; + let block_else_to_jump = elifs.iter().rev().try_fold( + last_block, + |last_block, current_block| { + let block_elif_predicate = + LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("block_elif"), + ); + let block_elif_then = LLVMAppendBasicBlockInContext( + context.context, + context.current_function.unwrap().0, + as_str!("block_elif"), + ); + LLVMPositionBuilderAtEnd( + context.builder, + block_elif_predicate, + ); + let (elif_predicate, type_of_elif_predicate) = + current_block.0.emit(context)?; + + if type_of_elif_predicate != Type::Bool { + return Err(( + "predicate is not an boolean".to_string(), + *location, + )); + } + + LLVMBuildCondBr( + context.builder, + elif_predicate, + block_elif_then, + last_block, + ); + LLVMPositionBuilderAtEnd( + context.builder, + block_elif_then, + ); + context.symbol_table.initialize_scope(); + current_block.1.emit(context)?; + context.symbol_table.kill_scope(); + LLVMBuildBr(context.builder, block_merge); + + Ok(block_elif_predicate) + }, + )?; + + LLVMPositionBuilderAtEnd(context.builder, block_if_predicate); + let (cmp_expression, type_of) = expression.emit(context)?; + if type_of != Type::Bool { + return Err(( + "Predicado não é booleano".to_string(), + *location, + )); + } + + LLVMBuildCondBr( + context.builder, + cmp_expression, + block_if_then, + block_else_to_jump, + ); + LLVMPositionBuilderAtEnd(context.builder, block_if_then); + context.symbol_table.initialize_scope(); + block.emit(context)?; + context.symbol_table.kill_scope(); + LLVMBuildBr(context.builder, block_merge); + LLVMPositionBuilderAtEnd(context.builder, block_merge); + + Ok(()) + } + Stmt::Write(list_expr, location) => { + let printf_fn = + match context.symbol_table.get("0printf").unwrap() { + Symbol::Func(value, _type_of) => value, + _ => panic!("What"), + }; + + let format_str = LLVMBuildGlobalStringPtr( + context.builder, + as_str!("%s"), + as_str!("format_str"), + ); + + let format_int = LLVMBuildGlobalStringPtr( + context.builder, + as_str!("%d"), + as_str!("format_int"), + ); + + let format_barra_n = LLVMBuildGlobalStringPtr( + context.builder, + as_str!("\n"), + as_str!("barra_n"), + ); + + list_expr + .iter() + .try_for_each::<_, Result<(), SemanticError>>(|expr| { + let (value, type_of) = + expr.emit(&mut context.clone())?; + + match type_of { + Type::Int | Type::Bool => { + LLVMBuildCall( + context.builder, + *printf_fn, + vec![format_int, value].as_mut_ptr(), + 2, + as_str!("call_write"), + ); + } + Type::Str => { + LLVMBuildCall( + context.builder, + *printf_fn, + vec![format_str, value].as_mut_ptr(), + 2, + as_str!("call_write"), + ); + } + _ => { + return Err(( + "type not writeable".to_string(), + *location, + )); + } + }; + + Ok(()) + })?; + + LLVMBuildCall( + context.builder, + *printf_fn, + vec![format_barra_n].as_mut_ptr(), + 1, + as_str!("call_write"), + ); + + Ok(()) + } + Stmt::Read(variable, location) => { + let format_int = LLVMBuildGlobalStringPtr( + context.builder, + as_str!("%d"), + as_str!("format_int"), + ); + + let scanf_fn = match context.symbol_table.get("0scanf").unwrap() + { + Symbol::Func(value, _type_of) => value, + _ => panic!("What"), + }; + + let (variable_ptr, type_of) = + variable.emit(&mut context.clone())?; + + if type_of != Type::Int { + return Err(( + "Output must be an integer".to_string(), + *location, + )); + } + + LLVMBuildCall( + context.builder, + *scanf_fn, + vec![format_int, variable_ptr].as_mut_ptr(), + 2, + as_str!("call_read"), + ); + + Ok(()) + } + } + } +} + +impl Emit<()> for Decl { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(), (String, Location)> { + if context.current_function.is_some() { + // When local + let alloc_builder = LLVMCreateBuilderInContext(context.context); + let first_intr = + LLVMGetFirstInstruction(context.current_function.unwrap().1); + if !first_intr.is_null() { + LLVMPositionBuilderBefore(alloc_builder, first_intr); + } else { + LLVMPositionBuilderAtEnd( + alloc_builder, + context.current_function.unwrap().1, + ); + } + + let builder = context.builder; + match self { + Decl::Single(identifier, type_of, expression, location) => { + match type_of { + Type::Str => { + if let Some(expression) = expression { + let (string, _) = expression.emit(context)?; + + if context + .symbol_table + .set( + identifier, + Symbol::Variable( + string, + type_of.clone(), + ), + ) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + Ok(()) + } else { + Err(( + "String must be initialized".to_string(), + *location, + )) + } + } + _ => { + let ptr_vlr = LLVMBuildAlloca( + alloc_builder, + type_of.emit(context).unwrap(), + as_str!(identifier), + ); + + if context + .symbol_table + .set( + identifier, + Symbol::Variable(ptr_vlr, type_of.clone()), + ) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + if let Some(expression) = expression { + let (expression, type_of_expression) = + expression.emit(context).unwrap(); + if type_of_expression != *type_of { + return Err(( + "Type of expression mismatch variable" + .to_string(), + *location, + )); + } + LLVMBuildStore(builder, expression, ptr_vlr); + Ok(()) + } else { + Ok(()) + } + } + } + } + Decl::Array( + identifier, + type_of, + size, + list_expression, + location, + ) => { + // TODO Initialize array + let (expression_size, _) = + Expr::Number(*size, *location).emit(context).unwrap(); + + let ptr_vlr = LLVMBuildArrayAlloca( + context.builder, + type_of.emit(context).unwrap(), + expression_size, + as_str!(identifier), + ); + if context + .symbol_table + .set( + identifier, + Symbol::Array(ptr_vlr, type_of.clone()), + ) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + if let Some(list_expression) = list_expression { + list_expression.iter().enumerate().try_for_each( + |(index, element)| { + Stmt::Attr( + Variable::Array( + identifier.to_owned(), + Box::new(Expr::Number( + index as u64, + *location, + )), + *location, + ), + element.clone(), + *location, + ) + .emit(context)?; + Ok(()) + }, + )?; + } + + Ok(()) + } + _ => panic!("Function not expected".to_string()), + } + } else { + // When global + match self { + Decl::Single(identifier, type_of, expression, location) => { + let decl = LLVMAddGlobal( + context.module, + type_of.emit(context).unwrap(), + as_str!(identifier), + ); + + if context + .symbol_table + .set( + identifier, + Symbol::Variable(decl, type_of.clone()), + ) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + if let Some(expression) = expression { + let (value, type_of_expression) = + expression.emit(context)?; + + if *type_of != type_of_expression { + return Err(( + "Initializer type mismtach variable type" + .to_string(), + *location, + )); + } + + LLVMSetInitializer(decl, value); + } + + Ok(()) + } + Decl::Array( + identifier, + type_of, + size, + _list_expression, + location, + ) => { + // TODO Initialize array + let array_type = LLVMArrayType( + type_of.emit(context).unwrap(), + *size as u32, + ); + + let decl = LLVMAddGlobal( + context.module, + array_type, + as_str!(identifier), + ); + + if context + .symbol_table + .set(identifier, Symbol::Array(decl, type_of.clone())) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + // TODO Initialization + + Ok(()) + } + Decl::Func( + identifier, + return_type, + vec_params, + block, + location, + ) => { + let vec_params = vec_params.clone().unwrap_or_default(); + + let mut args = vec_params + .iter() + .map(|param| match param { + FuncParam::Single(_, type_of, _) => { + type_of.emit(context).unwrap() + } + FuncParam::Array(_, type_of, _) => { + type_of.emit(context).unwrap() + } + }) + .collect::>(); + + let function_type = LLVMFunctionType( + return_type + .clone() + .unwrap_or_default() + .emit(context) + .unwrap(), + args.as_mut_ptr(), + args.len() as u32, + false as i32, + ); + let function = LLVMAddFunction( + context.module, + as_str!(identifier), + function_type, + ); + + if context + .symbol_table + .set( + identifier, + Symbol::Func( + function, + ( + return_type.clone().unwrap_or_default(), + vec_params + .iter() + .map(|param| match param { + FuncParam::Single( _, type_of, _,) + | FuncParam::Array(_, type_of, _) => type_of.clone(), + }) + .collect::>(), + ), + ), + ) + .is_err() + { + return Err(( + format!( + "Identifier {} already declared", + identifier + ), + *location, + )); + } + + let entry_block = LLVMAppendBasicBlockInContext( + context.context, + function, + as_str!("entry"), + ); + + context.symbol_table.initialize_scope(); + + context.current_function = Some((function, entry_block)); + LLVMPositionBuilderAtEnd(context.builder, entry_block); + + vec_params.iter().enumerate().for_each(|(index, param)| { + let function_param = + LLVMGetParam(function, index as u32); + + match param { + FuncParam::Single( + identifier, + type_of, + _location, + ) => { + let ptr_vlr = LLVMBuildAlloca( + context.builder, + type_of.emit(context).unwrap(), + as_str!(identifier), + ); + context + .symbol_table + .set( + &identifier, + Symbol::Variable( + ptr_vlr, + type_of.clone(), + ), + ) + .unwrap(); + + LLVMBuildStore( + context.builder, + function_param, + ptr_vlr, + ); + } + FuncParam::Array( + identifier, + type_of, + _location, + ) => { + let ptr_vlr = LLVMBuildAlloca( + context.builder, + type_of.emit(context).unwrap(), + as_str!(identifier), + ); + context + .symbol_table + .set( + &identifier, + Symbol::Array(ptr_vlr, type_of.clone()), + ) + .unwrap(); + + LLVMBuildStore( + context.builder, + function_param, + ptr_vlr, + ); + } + } + }); + + block.emit(context)?; + + context.symbol_table.kill_scope(); + + if !return_type.is_some() { + LLVMBuildRetVoid(context.builder); + } + + context.current_function = None; + Ok(()) + } + } + } + } +} + +impl Emit<()> for Block { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(), (String, Location)> { + for decl in self.decl.iter() { + decl.emit(context)?; + } + for command in self.commands.iter() { + command.emit(context)?; + } + + Ok(()) + } +} + +impl Emit<()> for Either { + unsafe fn emit( + self: &Self, + context: &mut Context, + ) -> Result<(), (String, Location)> { + match self { + Either::Left(stmt) => stmt.emit(context)?, + Either::Right(block) => block.emit(context)?, + }; + + Ok(()) + } +} diff --git a/src/gen/mod.rs b/src/gen/mod.rs new file mode 100644 index 0000000..33039d8 --- /dev/null +++ b/src/gen/mod.rs @@ -0,0 +1,42 @@ +use codespan::CodeMap; +use codespan_reporting::{ + emit, + termcolor::{ColorChoice, StandardStream}, + Diagnostic, Label, +}; +use std::{ffi::CString, process::exit}; + +#[macro_use] +macro_rules! as_str { + ($s:expr) => { + CString::new($s.clone()).unwrap().as_ptr() + }; +} + +use self::emit::Emit; +use ast::*; +use llvm::core::*; + +mod context; +mod emit; +mod symbol_table; + +pub unsafe fn gen(decls: Vec, code_map: &CodeMap) { + let mut context = context::Context::new(); + context.declare_printf_scanf(); + for i in decls { + let writer = StandardStream::stderr(ColorChoice::Always); + if let Err((msg, span)) = i.emit(&mut context) { + let diagnostic = Diagnostic::new_error(msg); + let label = Label::new_primary(span); + emit(writer, &code_map, &diagnostic.with_label(label)).unwrap(); + exit(127); + } + } + LLVMPrintModuleToFile( + context.module, + as_str!("test.ll"), + as_str!("idk") as *mut *mut i8, + ); + LLVMContextDispose(context.context); +} diff --git a/src/symbol_table.rs b/src/gen/symbol_table.rs similarity index 68% rename from src/symbol_table.rs rename to src/gen/symbol_table.rs index 1470393..58c43f2 100644 --- a/src/symbol_table.rs +++ b/src/gen/symbol_table.rs @@ -1,13 +1,15 @@ +use super::super::ast::Type; use std::collections::{HashMap, LinkedList}; use llvm::prelude::*; +// TODO Should store the type #[derive(Clone, Debug)] pub enum Symbol { - Variable(LLVMValueRef), - Array(u32, LLVMValueRef), - ArrayRef(LLVMValueRef), - Func(String), + Variable(LLVMValueRef, Type), + Array(LLVMValueRef, Type), + JumpBlock(LLVMBasicBlockRef), + Func(LLVMValueRef, (Type, Vec)), // TODO Should store tha function value and signature } #[derive(Clone, Debug)] @@ -45,8 +47,17 @@ impl SymbolTable { /// This function only set a identifier in the scope, possibly it will /// overwrite the value thats is current in the actual scope - pub fn set(self: &mut Self, identifier: &str, symbol: Symbol) { + pub fn set( + self: &mut Self, + identifier: &str, + symbol: Symbol, + ) -> Result<(), ()> { let front = self.list.front_mut().unwrap(); - front.insert(identifier.to_string(), symbol); + if front.get(identifier).is_some() { + Err(()) + } else { + front.insert(identifier.to_string(), symbol); + Ok(()) + } } } diff --git a/src/grammar/mod.lalrpop b/src/grammar/mod.lalrpop index 0b44a15..f1178b0 100644 --- a/src/grammar/mod.lalrpop +++ b/src/grammar/mod.lalrpop @@ -1,4 +1,5 @@ -use lalrpop_util::{ ErrorRecovery, ParseError }; +use lalrpop_util::{ ErrorRecovery }; +use codespan::{ ByteIndex, Span }; use std::str::FromStr; use ast::*; @@ -55,14 +56,27 @@ match { Num: u64 = r"[0-9]+" => u64::from_str(<>).unwrap(); Id: String = r"[a-zA-Z_][a-zA-Z0-9_]*" => String::from(<>); +String_Litteral: String = => s[1..s.len()-1].to_string(); Var: Variable = { - OPEN_BRACKET CLOSE_BRACKET => Variable::Array(<>), - => Variable::Single(<>), + OPEN_BRACKET CLOSE_BRACKET => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Variable::Array(i, e, location) + }, + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Variable::Single(i, location) + } }; Tier: Box = { - Tier Op Next => Box::new(Expr::Op(<>)), + > => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Op(e1, o, e2, location)) + }, Next, }; @@ -88,23 +102,56 @@ Either: (Option, Option) = { }; Term: Box = { - TRUE => Box::new(Expr::True), - FALSE => Box::new(Expr::False), - Num => Box::new(Expr::Number(<>)), - Var => Box::new(Expr::Variable(<>)), - OPEN_PARENS ?> CLOSE_PARENS => Box::new(Expr::Call(<>)), + TRUE => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::True(location)) + }, + FALSE => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::False(location)) + }, + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Number(n, location)) + }, + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::StringLitteral(s, location)) + }, + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Variable(v, location)) + }, + OPEN_PARENS ?> CLOSE_PARENS => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Call(i, e, location)) + }, OPEN_PARENS CLOSE_PARENS, }; NegativeOp: Opcode = MINUS => Opcode::Negative; Negative: Box = { - NegativeOp Term => Box::new(Expr::Right(<>)), + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Right(o, e, location)) + }, Term, }; NotOp: Opcode = EXCLAMATION => Opcode::Not; Not: Box = { - NotOp Negative=> Box::new(Expr::Right(<>)), + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Right(o, e, location)) + }, Negative, }; @@ -146,7 +193,11 @@ OrOp: Opcode = PIPE PIPE => Opcode::Or; Or = Tier; Ternary: Box = { - QUESTION COLON => Box::new(Expr::Ternary(<>)), + QUESTION COLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Box::new(Expr::Ternary(p, t, e, location)) + }, Or, }; @@ -158,15 +209,30 @@ Type: Type = { STR => Type::Str, }; -VarArrayDecl: (String, u64, Option>>) = { - // TODO Possible error recovery is when a user insert an expression in place of a number - OPEN_BRACKET CLOSE_BRACKET EQUAL OPEN_BRACE > CLOSE_BRACE => (a, n, Some(f)), - OPEN_BRACKET CLOSE_BRACKET => (a, n, None), +VarArrayDecl: (String, u64, Option>>, Span) = { + OPEN_BRACKET CLOSE_BRACKET EQUAL OPEN_BRACE > CLOSE_BRACE => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (a, n, Some(f), location) + }, + OPEN_BRACKET CLOSE_BRACKET => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (a, n, None, location) + } }; -VarSingleDecl: (String, Option>) = { - EQUAL => (i, Some(e)), - => (<>, None), +VarSingleDecl: (String, Option>, Span) = { + EQUAL => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (i, Some(e), location) + }, + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (i, None, location) + } }; VarDeclList = Comma>; @@ -176,39 +242,47 @@ VarDecl: Vec = { let mut f = Vec::new(); for i in d { if let Some(j) = i.0 { - f.push(Decl::Single(j.0, t.clone(), j.1)); + f.push(Decl::Single(j.0, t.clone(), j.1, j.2)); } else if let Some(j) = i.1 { - f.push(Decl::Array(j.0, t.clone(), j.1, j.2)); + f.push(Decl::Array(j.0, t.clone(), j.1, j.2, j.3)); } } f }, }; -ParamArrayDecl: String = { - OPEN_BRACKET CLOSE_BRACKET => <>, +ParamArrayDecl: (String, Span) = { + OPEN_BRACKET CLOSE_BRACKET => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (i, location) + }, }; -ParamSingleDecl: String = { - => <>, +ParamSingleDecl: (String, Span) = { + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (i, location) + }, }; ParamDeclList = Comma>; -FuncDecl: Decl = DEF OPEN_PARENS COLON )>?> CLOSE_PARENS )?> => { - // TODO Register the location of function declaration to show to the user in case of redeclaration +FuncDecl: Decl = DEF OPEN_PARENS COLON )>?> CLOSE_PARENS )?> => { let mut parameters_vector = Vec::new(); + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + if let Some(parameter_list) = p { for parameter in parameter_list { // parameter is an tuple of (list, type) - let declaration_list = parameter.0; - let type_of = parameter.1; + let ( declaration_list, type_of ) = parameter; for declaration in declaration_list { // !! The declaration is a parser Either not an AST::Either - if let Some(identifier) = declaration.0 { // If either is fullfiled in the left is a single variable - parameters_vector.push(FuncParam::Single(identifier, type_of.clone())); - } else if let Some(identifier) = declaration.1 { // Else if is fullfiled in the right side is an array - parameters_vector.push(FuncParam::Array(identifier, type_of.clone())); + if let Some((identifier, location)) = declaration.0 { // If either is fullfiled in the left is a single variable + parameters_vector.push(FuncParam::Single(identifier, type_of.clone(), location)); + } else if let Some((identifier, location)) = declaration.1 { // Else if is fullfiled in the right side is an array + parameters_vector.push(FuncParam::Array(identifier, Type::Agg(Box::new(type_of.clone())), location)); } } } @@ -216,9 +290,9 @@ FuncDecl: Decl = DEF OPEN_PARENS COLON function return type, could be None, when it's a procedure // parameter_list -- Could be None, when it does not have any parameter // b -> function block - Decl::Func(i, t, Some(parameters_vector), b) // When have parameters + Decl::Func(i, t, Some(parameters_vector), b, location) // When have parameters } else { - Decl::Func(i, t, None, b) // When does not have parameter + Decl::Func(i, t, None, b, location) // When does not have parameter } }; @@ -227,8 +301,12 @@ Decl: Vec = { FuncDecl => vec![<>], }; -Attr: (Variable, Box) = { - => (v.clone(), Box::new(Expr::Op(Box::new(Expr::Variable(v)), o, e))), +Attr: (Variable, Box, Span) = { + => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + (v.clone(), Box::new(Expr::Op(Box::new(Expr::Variable(v, location)), o, e, location)), location) + } }; AddEqual: Opcode = PLUS EQUAL => Opcode::Add; @@ -238,52 +316,98 @@ DivEqual: Opcode = SLASH EQUAL => Opcode::Div; ModEqual: Opcode = PERCENT EQUAL => Opcode::Mod; AllAttr: Stmt = { - EQUAL => Stmt::Attr(v, e), - PLUS PLUS => Stmt::Attr( - v.clone(), - Box::new( - Expr::Op( - Box::new(Expr::Variable(v)), - Opcode::Add, - Box::new(Expr::Number(1)) - ) + EQUAL => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Attr(v, e, location) + }, + PLUS PLUS => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Attr( + v.clone(), + Box::new( + Expr::Op( + Box::new(Expr::Variable(v, location)), + Opcode::Add, + Box::new(Expr::Number(1, location)), + location + ) + ), + location ) - ), - MINUS MINUS => Stmt::Attr( - v.clone(), - Box::new( - Expr::Op( - Box::new(Expr::Variable(v)), - Opcode::Sub, - Box::new(Expr::Number(1)) - ) + }, + MINUS MINUS => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Attr( + v.clone(), + Box::new( + Expr::Op( + Box::new(Expr::Variable(v, location)), + Opcode::Sub, + Box::new(Expr::Number(1, location)), + location + ) + ), + location ) - ), - > => Stmt::Attr(a.0, a.1), - > => Stmt::Attr(a.0, a.1), - > => Stmt::Attr(a.0, a.1), - > => Stmt::Attr(a.0, a.1), - > => Stmt::Attr(a.0, a.1), + }, + > => Stmt::Attr(a.0, a.1, a.2), + > => Stmt::Attr(a.0, a.1, a.2), + > => Stmt::Attr(a.0, a.1, a.2), + > => Stmt::Attr(a.0, a.1, a.2), + > => Stmt::Attr(a.0, a.1, a.2), }; Stmt: Stmt = { SEMICOLON => <>, - SKIP SEMICOLON => Stmt::Skip, - STOP SEMICOLON => Stmt::Stop, - RETURN SEMICOLON => Stmt::Return(<>), + SKIP SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); - READ SEMICOLON => Stmt::Read(<>), - WRITE > SEMICOLON => Stmt::Write(<>), + Stmt::Skip(location) + }, + STOP SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Stop(location) + }, + RETURN SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Return(e, location) + }, + READ SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Read(v, location) + }, + WRITE > SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); - // FIXME Function call is an expression not an statement - OPEN_PARENS ?> CLOSE_PARENS SEMICOLON => Stmt::Call(<>), + Stmt::Write(e, location) + }, + OPEN_PARENS ?> CLOSE_PARENS SEMICOLON => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::Call(i, e, location) + }, + IF OPEN_PARENS CLOSE_PARENS CLOSE_PARENS )*> )?> => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); - IF OPEN_PARENS CLOSE_PARENS <(ELSE IF OPEN_PARENS CLOSE_PARENS )*> <(ELSE )?> => Stmt::If(<>), + Stmt::If(e, b, elifs, e_block, location) + }, + WHILE OPEN_PARENS CLOSE_PARENS => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); - WHILE OPEN_PARENS CLOSE_PARENS => Stmt::While(<>), - // TODO If for does not accpet an a empty initialization or step recovery from error and print to user - FOR OPEN_PARENS SEMICOLON SEMICOLON CLOSE_PARENS => Stmt::For(Box::new(i), e, Box::new(s), b), + Stmt::While(e, b, location) + }, + FOR OPEN_PARENS SEMICOLON SEMICOLON CLOSE_PARENS => { + let location = Span::new(ByteIndex(l as u32), ByteIndex(r as u32)); + + Stmt::For(Box::new(i), e, Box::new(s), b, location) + } }; Commands: Either = { diff --git a/src/main.rs b/src/main.rs index a350ade..f05bf19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #![allow(unknown_lints)] #![warn(clippy::all)] +#![feature(dbg_macro)] extern crate clap; extern crate codespan; @@ -11,7 +12,6 @@ extern crate llvm_sys as llvm; mod ast; mod gen; mod grammar; -mod symbol_table; use clap::{ app_from_crate, crate_authors, crate_description, crate_name, @@ -61,7 +61,7 @@ fn main() { unsafe { let mut erros = vec![]; match grammar::ProgramParser::new().parse(&mut erros, &file.src()) { - Ok(expr) => gen::gen(expr), + Ok(expr) => gen::gen(expr, &code_map), Err(err) => match err { ParseError::UnrecognizedToken { token, expected } => { let (start, token, end) = match token { @@ -118,7 +118,7 @@ fn main() { .unwrap(); let diagnostic = - Diagnostic::new_error("invalid line or EOF"); + Diagnostic::new_error("Token inválido"); let label = Label::new_primary(span); emit(writer, &code_map, &diagnostic.with_label(label)) @@ -128,121 +128,3 @@ fn main() { } } } - -#[test] -fn parse_var_decl_with_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let a = 2 : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ast::Decl::Single( - "a".to_string(), - ast::Type::Int, - Some(Box::new(ast::Expr::Number(2))) - )] - ); -} - -#[test] -fn parse_var_decl_without_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let a : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ast::Decl::Single("a".to_string(), ast::Type::Int, None)] - ); -} - -#[test] -fn parse_var_multi_decl_without_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let a, b,c : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ - ast::Decl::Single("a".to_string(), ast::Type::Int, None), - ast::Decl::Single("b".to_string(), ast::Type::Int, None), - ast::Decl::Single("c".to_string(), ast::Type::Int, None) - ] - ); -} - -#[test] -fn parse_var_multi_decl_with_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let a = 1, b =2,c = 3 : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ - ast::Decl::Single( - "a".to_string(), - ast::Type::Int, - Some(Box::new(ast::Expr::Number(1))) - ), - ast::Decl::Single( - "b".to_string(), - ast::Type::Int, - Some(Box::new(ast::Expr::Number(2))) - ), - ast::Decl::Single( - "c".to_string(), - ast::Type::Int, - Some(Box::new(ast::Expr::Number(3))) - ) - ] - ); -} - -#[test] -fn parse_var_decl_with_expr_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let a = b + 1 : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ast::Decl::Single( - "a".to_string(), - ast::Type::Int, - Some(Box::new(ast::Expr::Op( - Box::new(ast::Expr::Variable(ast::Variable::Single( - "b".to_string() - ))), - ast::Opcode::Add, - Box::new(ast::Expr::Number(1)) - ))) - )] - ); -} - -#[test] -fn parse_var_decl_array_int_without_init() { - let mut errors = vec![]; - - let var_decl = grammar::ProgramParser::new() - .parse(&mut errors, "let v[10] : int;") - .unwrap(); - - assert_eq!( - var_decl, - [ast::Decl::Array("v".to_string(), ast::Type::Int, 10, None)] - ); -}