diff --git a/src/IR/parser/lexer.rs b/src/IR/parser/lexer.rs index af43eed4..bdcba1e8 100644 --- a/src/IR/parser/lexer.rs +++ b/src/IR/parser/lexer.rs @@ -350,7 +350,7 @@ impl IrLexer { } } - self.no_pop = false; + self.no_pop = true; Ok(TokenType::Var(out)) } @@ -490,6 +490,8 @@ impl IrLexer { out = -out; } + self.no_pop = true; + Ok(TokenType::Int(out)) } diff --git a/src/IR/parser/parser.rs b/src/IR/parser/parser.rs index bad4e9a6..fdd7429c 100644 --- a/src/IR/parser/parser.rs +++ b/src/IR/parser/parser.rs @@ -408,13 +408,21 @@ impl IrParser { self.expect(TokenType::Ident(String::new()))?; // node if let TokenType::Ident(instrinc) = &self.current_token()?.typ { - match instrinc.as_str() { - "call" => self.parse_call(name)?, - _ => { - let ty = self.parse_type()?; - self.input.pop_front(); // the type - self.parse_const_assing(name, ty)? - } + match instrinc.as_str() { + "sub" => self.parse_sub(name)?, + "add" => self.parse_add(name)?, + "mul" => self.parse_mul(name)?, + "cast" => self.parse_cast(name)?, + "xor" => self.parse_xor(name)?, + "or" => self.parse_or(name)?, + "and" => self.parse_and(name)?, + "div" => self.parse_div(name)?, + "call" => self.parse_call(name)?, + _ => { + let ty = self.parse_type()?; + self.input.pop_front(); // the type + self.parse_const_assing(name, ty)? + } } } else { unreachable!() } } else if let TokenType::Ident(instrinc) = curr.typ { @@ -565,6 +573,35 @@ impl IrParser { }))) } + fn parse_cast(&mut self, var: String) -> Result, IrError> { + self.input.pop_front(); + + self.expect(TokenType::Var(String::new()))?; + + let in_var = if let TokenType::Var(name) = &self.current_token()?.typ { + Var { + name: name.to_owned(), + ty: TypeMetadata::i32, + } + } else { unreachable!() }; + + self.input.pop_front(); + + self.expect_ident("to".into())?; + self.input.pop_front(); + + let out_ty = self.parse_type()?; + + self.input.pop_front(); + + let out = Var { + name: var, + ty: out_ty + }; + + Ok(ir::Cast::new(in_var, out_ty, out)) + } + fn parse_data_array(&mut self) -> Result, IrError> { self.expect(TokenType::LSquare)?; self.input.pop_front(); @@ -615,6 +652,30 @@ impl IrParser { } } + fn expect_ident(&mut self, expected: String) -> Result<(), IrError> { + self.expect(TokenType::Ident(String::new()))?; + + let ident = &self.current_token()?.typ; + + let ident = if let TokenType::Ident(ident) = ident { + ident + } else { + unreachable!() + }; + + if ident.to_owned() != expected { + Err(IrError::ExpectedTokenButFoundAnUnexpectedOne { + found: self.current_token()?.clone(), + expected: Token { + typ: TokenType::Ident(expected.to_owned()), + loc: self.current_token()?.loc.clone() + } + })? + } + + Ok(()) + } + fn parse_type(&mut self) -> Result { let token = self.current_token()?; @@ -638,4 +699,103 @@ impl IrParser { Err(IrError::UnkownType(token.clone()) ) } } -} \ No newline at end of file +} + +macro_rules! ParserImplParseMath { + ($func:ident, $node:ident) => { + impl IrParser { + fn $func(&mut self, var: String) -> Result, IrError> { + self.input.pop_front(); // add/sub/xor/or/and/mul/div + + let ty = self.parse_type()?; + self.input.pop_front(); // out_ty + + let out = Var { + name: var, + ty: ty, + }; + + let curr = self.current_token()?; + + Ok(match &curr.typ { + TokenType::Int(op1) => { + let op1 = *op1; + + self.input.pop_front(); // num1 + + self.expect(TokenType::Comma)?; + self.input.pop_front(); // , + + self.expect(TokenType::Int(0))?; + let op2; + if let TokenType::Int(int) = &self.current_token()?.typ { + op2 = *int; + } else { unreachable!() } + + self.input.pop_front(); + + let op1 = Type::from_int(ty, op1); + let op2 = Type::from_int(ty, op2); + + ir::$node::new(op1, op2, out) + }, + + TokenType::Var(op1) => { + let op1 = op1.to_owned(); + + self.input.pop_front(); // op1 + + self.expect(TokenType::Comma)?; + self.input.pop_front(); + + if let TokenType::Var(var) = &self.current_token()?.typ { + let op1 = Var { + name: op1, + ty: ty + }; + + let op2 = Var { + name: var.to_owned(), + ty: ty + }; + + self.input.pop_front(); + + ir::$node::new(op1, op2, out) + } else if let TokenType::Int(op) = &self.current_token()?.typ { + let op1 = Var { + name: op1, + ty: ty + }; + + let op2 = Type::from_int(ty, *op); + + self.input.pop_front(); + + ir::$node::new(op1, op2, out) + } else { + Err(IrError::ExpectedTokenButFoundAnUnexpectedOne { + found: self.current_token()?.to_owned(), + + expected: Token { typ: TokenType::Var(") or Int()".into()), loc: Loc::default() }, + })? + } + }, + + _ => Err(IrError::ExpectedTokenButFoundAnUnexpectedOne { + expected: Token { typ: TokenType::Var(String::new()), loc: Loc::default() }, + found: curr.clone(), + })? + }) + } + } + }; +} + +ParserImplParseMath!(parse_add, Add); +ParserImplParseMath!(parse_sub, Sub); +ParserImplParseMath!(parse_xor, Xor); +ParserImplParseMath!(parse_or, Or ); +ParserImplParseMath!(parse_and, And); +ParserImplParseMath!(parse_mul, Mul); +ParserImplParseMath!(parse_div, Div); \ No newline at end of file diff --git a/src/IR/parser/semnatic.rs b/src/IR/parser/semnatic.rs index 30a05d1d..912d6270 100644 --- a/src/IR/parser/semnatic.rs +++ b/src/IR/parser/semnatic.rs @@ -139,7 +139,51 @@ impl<'a> IrSemnatic<'a> { self.analyize_call(&mut vars, node, loc)?; } else if let Some(node) = any.downcast_ref::>>() { self.analiyze_block(func, node, loc)?; - } + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_add_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_sub_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_xor_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_or_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_and_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_mul_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_div_var_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_add_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_sub_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_xor_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_or_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_and_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_mul_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_div_ty_ty(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_add_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_sub_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_xor_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_or_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_and_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_mul_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_div_var_var(&mut vars, node, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analaysiz_cast(&mut vars, node, loc)?; + } } } @@ -313,6 +357,21 @@ impl<'a> IrSemnatic<'a> { Ok(()) } + fn analaysiz_cast(&mut self, vars: &mut HashMap, node: &Cast, loc: Loc) -> Result<(), IrError> { + if !vars.contains_key(&node.inner1.name) { + Err(IrError::Unkown { + loc: loc.to_owned(), + name: node.inner1.name.to_owned(), + + what: "variable".into(), + })? + } + + vars.insert(node.inner3.name.to_owned(), node.inner2); + + Ok(()) + } + fn analiyze_block(&mut self, func: &String, node: &Br>, loc: Loc) -> Result<(), IrError> { let br_block = &node.inner1.name; @@ -332,4 +391,114 @@ impl<'a> IrSemnatic<'a> { fn analyize_const(&mut self, _: &String, _: &Vec, _: &Loc, _: Linkage) -> Result<(), IrError> { Ok(()) // what can go wrong on constants? } -} \ No newline at end of file +} + +macro_rules! SemnaticImplMathVarTy { + ($func:ident, $node:ident) => { + impl<'a> IrSemnatic<'a> { + fn $func(&mut self, vars: &mut HashMap, node: &$node, loc: Loc) -> Result<(), IrError> { + if !vars.contains_key(&node.inner1.name) { + Err(IrError::Unkown { + loc: loc.to_owned(), + name: node.inner1.name.to_owned(), + + what: "variable".into(), + })? + } + + if vars.contains_key(&node.inner3.name) { + Err(IrError::DefinedTwice { + loc: loc.to_owned(), + name: node.inner3.name.to_owned(), + })? + } + + vars.insert(node.inner3.name.to_owned(), node.inner2.into()); + + Ok(()) + } + } + }; +} + +SemnaticImplMathVarTy!(analaysiz_add_var_ty, Add); +SemnaticImplMathVarTy!(analaysiz_sub_var_ty, Sub); +SemnaticImplMathVarTy!(analaysiz_xor_var_ty, Xor); +SemnaticImplMathVarTy!(analaysiz_or_var_ty, Or ); +SemnaticImplMathVarTy!(analaysiz_and_var_ty, And); +SemnaticImplMathVarTy!(analaysiz_mul_var_ty, Mul); +SemnaticImplMathVarTy!(analaysiz_div_var_ty, Div); + +macro_rules! SemnaticImplMathTyTy { + ($func:ident, $node:ident) => { + impl<'a> IrSemnatic<'a> { + fn $func(&mut self, vars: &mut HashMap, node: &$node, loc: Loc) -> Result<(), IrError> { + if vars.contains_key(&node.inner3.name) { + Err(IrError::DefinedTwice { + loc: loc.to_owned(), + name: node.inner3.name.to_owned(), + })? + } + + vars.insert(node.inner3.name.to_owned(), node.inner1.into()); + + Ok(()) + } + } + }; +} + +SemnaticImplMathTyTy!(analaysiz_add_ty_ty, Add); +SemnaticImplMathTyTy!(analaysiz_sub_ty_ty, Sub); +SemnaticImplMathTyTy!(analaysiz_xor_ty_ty, Xor); +SemnaticImplMathTyTy!(analaysiz_or_ty_ty, Or ); +SemnaticImplMathTyTy!(analaysiz_and_ty_ty, And); +SemnaticImplMathTyTy!(analaysiz_mul_ty_ty, Mul); +SemnaticImplMathTyTy!(analaysiz_div_ty_ty, Div); + +macro_rules! SemnaticImplMathVarVar { + ($func:ident, $node:ident) => { + impl<'a> IrSemnatic<'a> { + fn $func(&mut self, vars: &mut HashMap, node: &$node, loc: Loc) -> Result<(), IrError> { + if !vars.contains_key(&node.inner1.name) { + Err(IrError::Unkown { + loc: loc.to_owned(), + name: node.inner1.name.to_owned(), + + what: "variable".into(), + })? + } + + if !vars.contains_key(&node.inner2.name) { + Err(IrError::Unkown { + loc: loc.to_owned(), + name: node.inner2.name.to_owned(), + + what: "variable".into(), + })? + } + + if vars.contains_key(&node.inner3.name) { + Err(IrError::DefinedTwice { + loc: loc.to_owned(), + name: node.inner3.name.to_owned(), + })? + } + + let ty = if let Some(var) = vars.get(&node.inner2.name) { var } else { unreachable!() }; + + vars.insert(node.inner3.name.to_owned(), *ty); + + Ok(()) + } + } + }; +} + +SemnaticImplMathVarVar!(analaysiz_add_var_var, Add); +SemnaticImplMathVarVar!(analaysiz_sub_var_var, Sub); +SemnaticImplMathVarVar!(analaysiz_xor_var_var, Xor); +SemnaticImplMathVarVar!(analaysiz_or_var_var, Or ); +SemnaticImplMathVarVar!(analaysiz_and_var_var, And); +SemnaticImplMathVarVar!(analaysiz_mul_var_var, Mul); +SemnaticImplMathVarVar!(analaysiz_div_var_var, Div); \ No newline at end of file diff --git a/tests/IR/add0.yl b/tests/IR/add0.yl new file mode 100644 index 00000000..a00ec768 --- /dev/null +++ b/tests/IR/add0.yl @@ -0,0 +1,12 @@ +# RUN: +cargo run -p ylc -- -in=%s -o=out.o +gcc out.o -o a.exe +./a.exe +# IN: +define u32 @main() { + entry: + %1 = add u32 5, 6 + ret u32 %1 +} + +# EXIT_CODE=11 \ No newline at end of file diff --git a/tests/IR/add1.yl b/tests/IR/add1.yl new file mode 100644 index 00000000..b6340533 --- /dev/null +++ b/tests/IR/add1.yl @@ -0,0 +1,16 @@ +# RUN: +cargo run -p ylc -- -in=%s -o=out.o -asm-clr +gcc out.o -o a.exe +./a.exe +# IN: +define i32 @main() { + entry: + %0 = i32 5 + %1 = i32 64 + + %2 = add i32 %0, %1 + + ret i32 %2 +} + +# EXIT_CODE=69 \ No newline at end of file diff --git a/tests/IR/add2.yl b/tests/IR/add2.yl new file mode 100644 index 00000000..ce4d902d --- /dev/null +++ b/tests/IR/add2.yl @@ -0,0 +1,14 @@ +# RUN: +cargo run -p ylc -- -in=%s -o=out.o +gcc out.o -o a.exe +./a.exe +# IN: +define i32 @main() { + entry: + %0 = i32 134 + %1 = add i32 %0, 523 + + ret i32 %1 +} + +# EXIT_CODE=657 \ No newline at end of file diff --git a/tests/Optimizations/pre_value_calc.yl b/tests/Optimizations/pre_value_calc.yl new file mode 100644 index 00000000..0f612204 --- /dev/null +++ b/tests/Optimizations/pre_value_calc.yl @@ -0,0 +1,20 @@ +# RUN: +cargo run -p ylc -- -in=%s -o=out.o -O -fmt +gcc out.o -o a.exe +./a.exe +# IN: +define u32 @main() { + entry: + %1 = add i32 5, 6 + %2 = cast %1 to u32 + ret u32 %2 +} + +# EXIT_CODE=11 +# STDOUT: +define u32 @main() { + entry: + 1 = i32 11 + 2 = cast 1 to u32 + ret u32 2 +} \ No newline at end of file diff --git a/tools/ylc/main.rs b/tools/ylc/main.rs index 0c02f74a..23fcf983 100644 --- a/tools/ylc/main.rs +++ b/tools/ylc/main.rs @@ -3,6 +3,8 @@ use std::io::{Read, Write}; use std::process::exit; use std::error::Error; +use ygen::prelude::PassManager; +use ygen::Optimizations::Passes; use ygen::Support::{ColorProfile, Colorize}; use ygen::Target::initializeAllTargets; use ygen::{Support::Cli, Target::Triple}; @@ -30,6 +32,9 @@ fn main() -> Result<(), Box> { cli.add_opt("fmt-clr", "format-colored", "Reprints the ir to stderr with color information"); cli.add_opt("fmt", "format", "Prints the ir formatted to stdout"); + + cli.add_opt("O", "optimize-simple", "Run simple optimizations"); + cli.scan(); if cli.opt("h") { @@ -127,7 +132,15 @@ fn main() -> Result<(), Box> { gen.gen(); - let module: Module = gen.module(); + let mut module: Module = gen.module(); + + if cli.opt("O") { + let mut opts = PassManager::new(); + + opts.add( Passes::PreComputeValue() ); + + module.runPassMngr(opts); + } if cli.opt("fmt-clr") { eprintln!("{}", module.dumpColored(ColorProfile::default())); diff --git a/tools/ytest/main.rs b/tools/ytest/main.rs index e52e6dec..1b5f49d3 100644 --- a/tools/ytest/main.rs +++ b/tools/ytest/main.rs @@ -16,6 +16,7 @@ fn main() { cli.add_opt("v", "version", "Displays the version"); cli.add_opt("no-exit", "no-exit-on-error", "Ytest does not quite when an error occurs"); + cli.add_opt("neg-exit", "exit-code-neg", "Ytest exits automaticly even with `no-exit` if the programm returned with code -1"); cli.add_arg("t", "test", "The file to the testcase", true); @@ -113,13 +114,28 @@ fn main() { } let out = cmd.output().expect("failed to execute the process"); - found.push_str(str::from_utf8(&out.stdout).unwrap()); + let stdout = out.stdout; + + let stdout = str::from_utf8(&stdout).unwrap(); + let stdout = stdout.chars().filter(|x| !x.is_whitespace()).collect::(); + + found.push_str(&stdout); match cmd.status() { Ok(status) => { if !status.success() { - if let Some(exit) = status.code() { - code = exit; + if let Some(exit_code) = status.code() { + if parsed.expected_code == 0 || (cli.opt("exit") && code == -1) { + println!("{}: the programm didn't exit sucessfull with code {}", "Error".red().bold(), exit_code); + if !cli.opt("no-exit") { + exit(-1); + } + } else if cli.opt("neg-exit") && code == -1 { + println!("{}: the programm didn't exit sucessfull with code {}", "Error".red().bold(), exit_code); + exit(-1); + } else { + code = exit_code; + } } else { println!("{}: the programm didn't exit sucessfull", "Error".red().bold()); if !cli.opt("no-exit") { @@ -141,7 +157,7 @@ fn main() { if parsed.expected_out != found { println!("{}: expected output didn't match actual output", "Error".red().bold()); - println!("found: {:?}", found); + println!("found: {:?}", found); println!("expected: {:?}", parsed.expected_out); if !cli.opt("no-exit") { exit(-1) diff --git a/tools/ytest/parse.rs b/tools/ytest/parse.rs index b377f29e..e31411e6 100644 --- a/tools/ytest/parse.rs +++ b/tools/ytest/parse.rs @@ -46,6 +46,8 @@ pub fn parse(input: String) -> Parsed { append = false; } + let line = line.replace(" ", "\t"); + if append { if run { if !line.is_empty() { @@ -59,6 +61,8 @@ pub fn parse(input: String) -> Parsed { } } + out.expected_out = out.expected_out.chars().filter(|x| !x.is_whitespace()).collect::(); + //out.expected_out = unescaper::unescape(&out.expected_out).unwrap(); out