diff --git a/examples/add.acc b/examples/add.acc index 3ab2e6d..638ae81 100644 --- a/examples/add.acc +++ b/examples/add.acc @@ -27,7 +27,6 @@ fn %add_but_unused_bb(#a: i64, #b: i64) -> i64 { ret %5 } - fn %add_but_direct_link_bb(#a: i64, #b: i64) -> i64 { %3: let %4 = add #a, #b @@ -37,4 +36,31 @@ fn %add_but_direct_link_bb(#a: i64, #b: i64) -> i64 { ret %5 %6: ret %4 -} \ No newline at end of file +} + +fn %add_with_load_store_alloca(#1: i64, #2: i64) -> i64 { +%entry: + let %arg.1.addr = alloca i64, 1 + let %arg.2.addr = alloca i64, 1 + let %3 = store #1, %arg.1.addr + let %4 = store #2, %arg.2.addr + jmp label %6 +%6: + let %7 = load %arg.1.addr + let %8 = load %arg.2.addr + let %9: i64 = add %7, %8 + ret %9 +} + +fn %load_store_alloca_offset(#1: i64, #2: i64) -> i64 { +%entry: + let %arg.array = alloca i64, 6 + let %arg.1.addr = offset i64, %arg.array, [0 < 2], [1 < 3] + let %arg.2.addr = offset i64, %arg.array, [1 < 2], [2 < 3] + let %3 = store #1, %arg.1.addr + let %4 = store #2, %arg.2.addr + jmp label %6 +%6: + let %8 = load %arg.2.addr + ret %8 +} diff --git a/src/apps/executor.rs b/src/apps/executor.rs index 2e45400..ca2b1a4 100644 --- a/src/apps/executor.rs +++ b/src/apps/executor.rs @@ -1,7 +1,7 @@ use core::fmt; use std::collections::HashMap; -use crate::ir::{structures::*, values}; +use crate::ir::{structures::*, values::{self, ConstantInt}}; use slotmap::{SlotMap, SecondaryMap}; @@ -16,6 +16,8 @@ pub enum ExecutionError { NotImplemented(String), UnexpectedIncompatibleVal(Val), UseUndefinedValue, + LexerError, + ParseError } /// Trace the source of pointer values, @@ -290,7 +292,7 @@ pub fn single_step( // compute accumulated offset let last_dim_subdim = [Some(1usize)]; let total_offset: usize = indices - .into_iter().zip(inner.bounds.iter().cloned().chain(last_dim_subdim.into_iter())) + .into_iter().zip(inner.bounds.iter().cloned().skip(1).chain(last_dim_subdim.into_iter())) .fold(0usize, | acc, (index, next_dim_bound) | { acc + index * next_dim_bound.expect("expected bounded dimension in `Offset`") }); @@ -445,6 +447,20 @@ pub fn run_on_module( entry_fn: &str, args: Vec ) -> Result { + // set all constant value + module.value_ctx + .iter() + .for_each(| (value, value_data) | { + match &value_data.kind { + ValueKind::ConstantInt(inner) => + env.set_val(value, Val::Integer(inner.value)), + ValueKind::ConstantBool(inner) => + env.set_val(value, Val::Bool(inner.value)), + ValueKind::ConstantUnit(_) => + env.set_val(value, Val::Unit), + _ => None, + }; + }); let function = module.get_function_ref(entry_fn); run_on_function(env, module, function, args) } \ No newline at end of file diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index bfa2d86..711df33 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -194,18 +194,21 @@ impl Lexer { } pub fn lex(input: &str) -> IResult<&str, Vec> { - many0(alt(( - // `let` `le` has name collision. - lex_keyword, - lex_literal, - lex_identifier, - lex_primitive_type, - lex_delimiter, - lex_binary_operator, - lex_offset_operator, - lex_memory_operator, - lex_function_cal_operator, - lex_terminator_operator, + all_consuming( + many1(terminated(alt(( + // `let` `le` has name collision. + lex_keyword, + lex_literal, + lex_identifier, + lex_primitive_type, + lex_delimiter, + lex_binary_operator, + lex_offset_operator, + lex_memory_operator, + lex_function_cal_operator, + lex_terminator_operator, + )), + filter_whitespace_and_comment, )))(input) } } \ No newline at end of file diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index f00053f..c9701a7 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1,12 +1,13 @@ use std::cell::RefCell; use std::rc::Rc; use nom::{ - branch::alt, bytes::complete::{is_not, tag, take, take_until}, character::complete::{ - alpha0, alpha1, - alphanumeric0, alphanumeric1, - char, digit0, digit1, - multispace0, multispace1 - }, combinator::{all_consuming, map, map_res, opt, peek, recognize, value}, error::{Error, ErrorKind, ParseError}, multi::{fold_many1, many0, many0_count, many1, many1_count, separated_list0}, sequence::{delimited, pair, preceded, separated_pair, terminated, tuple}, Compare, CompareResult, Err, IResult, InputIter, InputLength, InputTake, Needed, Slice + branch::alt, + bytes::complete::take, + combinator::{all_consuming, map, opt, peek, value}, + error::{context, Error, ErrorKind, ParseError, VerboseError}, + multi::{fold_many1, many0, many0_count, many1, many1_count, separated_list0}, + sequence::{delimited, pair, preceded, separated_pair, terminated, tuple}, + Compare, CompareResult, Err, InputIter, InputLength, InputTake }; use crate::ir::{ @@ -16,6 +17,8 @@ use crate::ir::{ use super::{lexer::Lexer, token}; use super::token::{Token, Tokens}; +pub type IResult> = Result<(I, O), nom::Err>; + fn token<'a, Input, Error: ParseError>( t: Token<'a> @@ -44,7 +47,7 @@ fn identifier(input: Tokens) -> IResult { // println!("identifier {}, now token: {:?}", id, input); Ok((input, id)) }, - _ => Err(Err::Error(Error::new(input, ErrorKind::Tag))) + _ => Err(Err::Error(VerboseError::from_error_kind(input, ErrorKind::Tag))) } } @@ -52,7 +55,7 @@ fn i64_literal(input: Tokens) -> IResult { let (input, tk) = take(1usize)(input)?; match tk.iter_elements().next().unwrap() { Token::LtInt64(value) => Ok((input, value.clone())), - _ => Err(Err::Error(Error::new(input, ErrorKind::Tag))) + _ => Err(Err::Error(VerboseError::from_error_kind(input, ErrorKind::Tag))) } } @@ -60,7 +63,7 @@ fn i1_literal(input: Tokens) -> IResult { let (input, tk) = take(1usize)(input)?; match tk.iter_elements().next().unwrap() { Token::LtInt1(value) => Ok((input, value.clone())), - _ => Err(Err::Error(Error::new(input, ErrorKind::Tag))) + _ => Err(Err::Error(VerboseError::from_error_kind(input, ErrorKind::Tag))) } } @@ -167,7 +170,7 @@ impl<'a, 'b: 'a> Parser { builder .borrow() .get_value_ref(name) - .unwrap() + .expect("undefined symbol") }), map(parse_literal, | value: Value| { builder @@ -222,6 +225,119 @@ impl<'a, 'b: 'a> Parser { anno_ty ))) } + + fn parse_load( + input: Tokens<'a>, + builder: Rc> + ) -> IResult, ValueRef> { + let (input,(name, anno_ty)) = + delimited(token(Token::KwLet), parse_symbol, token(Token::Equal))(input)?; + + let (input, addr) = preceded( + token(Token::TkLoad), + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()) + )(input)?; + + Ok((input, builder.borrow_mut().emit_load( + Some(String::from(name)), + addr, + anno_ty + ))) + } + + fn parse_store( + input: Tokens<'a>, + builder: Rc> + ) -> IResult, ValueRef> { + let (input,(name, anno_ty)) = + delimited(token(Token::KwLet), parse_symbol, token(Token::Equal))(input)?; + + let (input, (stored, addr)) = preceded( + token(Token::TkStore), + separated_pair( + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()), + token(Token::Comma), + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()) + ))(input)?; + + Ok((input, builder.borrow_mut().emit_store( + Some(String::from(name)), + stored, + addr, + anno_ty + ))) + } + + fn parse_offset( + input: Tokens<'a>, + builder: Rc> + ) -> IResult, ValueRef> { + let (input,(name, anno_ty)) = + delimited(token(Token::KwLet), parse_symbol, token(Token::Equal))(input)?; + + let parse_bounds = alt(( + value(None, token(Token::LtNone)), + map(i64_literal, | lit | Some(usize::try_from(lit).expect("expect non-negative offset bound"))) + )); + + let (input, (base_ty, addr, indices_bounds)) = preceded( + token(Token::TkOffset), + tuple(( + parse_type, + preceded( + token(Token::Comma), + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()), + ), + many1( + preceded( + token(Token::Comma), + delimited( + token(Token::LBracket), + separated_pair( + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()), + token(Token::Less), + parse_bounds), + token(Token::RBracket) + ) + ) + ) + )) + )(input)?; + + Ok((input, builder.borrow_mut().emit_offset( + Some(String::from(name)), + base_ty, + addr, + indices_bounds, + anno_ty + ))) + } + + fn parse_fncall( + input: Tokens<'a>, + builder: Rc> + ) -> IResult, ValueRef> { + let (input,(name, anno_ty)) = + delimited(token(Token::KwLet), parse_symbol, token(Token::Equal))(input)?; + + let (input, ((callee, _), args)) = preceded( + token(Token::TkFnCall), + tuple(( + parse_symbol, + separated_list0( + token(Token::Comma), + | token: Tokens<'a> | Parser::parse_value(token, builder.clone()), + ) + )) + )(input)?; + + Ok((input, builder.borrow_mut().emit_function_call( + Some(String::from(name)), + String::from(callee), + args, + anno_ty + ))) + } fn parse_instruction( input: Tokens<'a>, @@ -229,6 +345,11 @@ impl<'a, 'b: 'a> Parser { ) -> IResult, ValueRef> { alt(( | input: Tokens<'a> | Parser::parse_binary_expr(input, builder.clone()), + | input: Tokens<'a> | Parser::parse_alloca(input, builder.clone()), + | input: Tokens<'a> | Parser::parse_load(input, builder.clone()), + | input: Tokens<'a> | Parser::parse_store(input, builder.clone()), + | input: Tokens<'a> | Parser::parse_offset(input, builder.clone()), + | input: Tokens<'a> | Parser::parse_fncall(input, builder.clone()), ))(input) } @@ -386,14 +507,11 @@ impl<'a, 'b: 'a> Parser { input: Tokens<'a>, builder: Rc> ) -> IResult, Module> { - let (input, _) = many0( + let (input, _) = all_consuming(many1( | input: Tokens<'a> | Parser::parse_function(input, builder.clone()) - )(input)?; - if input.input_len() > 0 { - Err(Err::Failure(Error::new(input, ErrorKind::Tag))) - } else { - Ok((input, builder.borrow().module.clone())) - } + ))(input)?; + + Ok((input, builder.borrow().module.clone())) } } diff --git a/src/ir/builders.rs b/src/ir/builders.rs index 04bd305..d15f766 100644 --- a/src/ir/builders.rs +++ b/src/ir/builders.rs @@ -364,7 +364,7 @@ impl IRBuilder { inner_name ); - let mut offset = values::Offset::new_value(addr_ty, addr, index, bound); + let mut offset = values::Offset::new_value(base_type, addr, index, bound); offset.set_name(inner_name); self.insert_instruction_symbol(offset) } diff --git a/src/ir/structures.rs b/src/ir/structures.rs index b21eead..ccb98eb 100644 --- a/src/ir/structures.rs +++ b/src/ir/structures.rs @@ -62,6 +62,10 @@ impl Value { ValueKind::Binary(..) | ValueKind::Offset(..) | ValueKind::FnCall(..) | ValueKind::Alloca(..) | ValueKind::Load(..) | ValueKind::Store(..)) } + + pub fn is_constant_value(&self) -> bool { + matches!(self.kind, ValueKind::ConstantInt(..) | ValueKind::ConstantBool(..) | ValueKind::ConstantUnit(..)) + } } impl fmt::Display for Value { @@ -264,6 +268,39 @@ impl fmt::Display for Module { let rhs = self.get_value(inner.rhs); write!(f, " let {} = {} {}, {}\n", value, inner.op, lhs, rhs) + }, + ValueKind::Load(inner) => { + let addr = self.get_value(inner.addr); + write!(f, " let {} = load {}\n", + value, addr) + }, + ValueKind::Store(inner) => { + let stored = self.get_value(inner.value); + let addr = self.get_value(inner.addr); + write!(f, " let {} = store {}, {}\n", + value, stored, addr) + }, + ValueKind::FnCall(inner) => { + let callee = inner.callee.clone(); + let args = inner.args.iter().cloned().map(| argref| self.get_value(argref)); + write!(f, " let {} = call {}, {}\n", + value, callee, args.format(", ")) + }, + ValueKind::Offset(inner) => { + let elem_type = inner.elem_type.clone(); + let addr = self.get_value(inner.base_addr); + let indices = inner.index.iter().cloned().map(| argref| self.get_value(argref)); + let bounds = inner.bounds.clone(); + write!(f, " let {} = offset {}, {}, {}\n", + value, elem_type, addr, + indices.into_iter().zip(bounds.into_iter()) + .format_with(", ", | (index, bound), f | { + match bound { + Some(bound) => f(&format_args!("[{} < {}]", index, bound)), + None => f(&format_args!("[{} < none]", index)) + } + }) + ) } _ => panic!("invalid instruction {}", value) }?; diff --git a/src/ir/values.rs b/src/ir/values.rs index 62219f7..056dcc7 100644 --- a/src/ir/values.rs +++ b/src/ir/values.rs @@ -137,14 +137,15 @@ impl ConstantUnit { #[derive(Debug, Clone)] pub struct Offset { + pub elem_type: Type, pub base_addr: ValueRef, pub index: Vec, pub bounds: Vec>, } impl Offset { - pub fn new_value(ty: Type, base_addr: ValueRef, index: Vec, bounds: Vec>) -> Value { - Value::new(ty, None, ValueKind::Offset(Self { base_addr, index, bounds })) + pub fn new_value(elem_type: Type, base_addr: ValueRef, index: Vec, bounds: Vec>) -> Value { + Value::new(Type::get_pointer(elem_type.clone()), None, ValueKind::Offset(Self { elem_type, base_addr, index, bounds })) } } diff --git a/src/main.rs b/src/main.rs index 3536c36..743c2d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::cell::RefCell; -use ariadne::*; -use chumsky::prelude::*; +use nom::*; +// use ariadne::*; +// use chumsky::prelude::*; use accipit::{ frontend::{ - token::Tokens, - new_lexer::lexer, + token::{Tokens, Token}, + lexer::Lexer, + parser::Parser, + // new_lexer::lexer, }, ir::{ builders::IRBuilder, @@ -19,44 +22,51 @@ use accipit::{ }; -fn main() { +fn main() -> Result<(), ExecutionError>{ let filename = std::env::args() .nth(1) .expect("expect input file"); let src = std::fs::read_to_string(&filename) .expect("failed to read input file"); - let (tokens, lex_errs) = lexer().parse(src.as_str()).into_output_errors(); - println!("{:?}", tokens); - // let (_, tokens) = Lexer::lex(&src) - // .finish() - // .inspect_err(| lex_err | { - // println!("Unrecognized token:\n{}", error::convert_error(src.as_str(), lex_err.clone())) - // }) - // .map_err(| err | ExecutionError::LexerError ).unwrap(); - // let token_wrapper = Tokens::new(&tokens); - // let builder = Rc::new(RefCell::new(IRBuilder::new())); - // let (_, module) = Parser::parse_from_complete_input(token_wrapper, builder).unwrap(); - // println!("Module:\n{}", module); + // let (tokens, lex_errs) = lexer().parse(src.as_str()).into_output_errors(); + // println!("{:?}", tokens); + let (_, tokens) = Lexer::lex(&src) + .finish() + .inspect_err(| lex_err | { + println!("Unrecognized token:\n{}", nom::error::convert_error(src.as_str(), lex_err.clone())) + }) + .map_err(| err | ExecutionError::LexerError ).unwrap(); + // println!("{:?}", tokens); + let token_wrapper = Tokens::new(&tokens); + let builder = Rc::new(RefCell::new(IRBuilder::new())); + let (_, module) = Parser::parse_from_complete_input(token_wrapper, builder) + .finish() + .inspect_err(| parser_err | { + println!("Parser Error:\n{:?}", parser_err) + }) + .map_err(| err | ExecutionError::ParseError ) + .unwrap(); + println!("Module:\n{}", module); - // let mut prog_env = ProgramEnv::new(); - // let args = vec![Val::Integer(1), Val::Integer(2)]; - // let interpreted = run_on_module(&mut prog_env, &module, "add_but_direct_link_bb", args); - // println!("Interepted: {:?}", interpreted); - // Ok(()) + let mut prog_env = ProgramEnv::new(); + let args = vec![Val::Integer(1), Val::Integer(2)]; + let interpreted = run_on_module(&mut prog_env, &module, "load_store_alloca_offset", args); + println!("Interepted: {:?}", interpreted); + Ok(()) - lex_errs.into_iter() - .map(| e | e.map_token(| c | c.to_string())) - .for_each(| e | { - Report::build(ReportKind::Error, filename.clone(), e.span().start) - .with_message(e.to_string()) - .with_label( - Label::new((filename.clone(), e.span().into_range())) - .with_message(e.to_string()) - .with_color(Color::Red) - ) - .finish() - .print(sources([(filename.clone(), src.clone())])) - .unwrap() - }); + // lex_errs.into_iter() + // .map(| e | e.map_token(| c | c.to_string())) + // .for_each(| e | { + // Report::build(ReportKind::Error, filename.clone(), e.span().start) + // .with_message(e.to_string()) + // .with_label( + // Label::new((filename.clone(), e.span().into_range())) + // .with_message(e.to_string()) + // .with_color(Color::Red) + // ) + // .finish() + // .print(sources([(filename.clone(), src.clone())])) + // .unwrap() + // }); }