diff --git a/crates/codegen/src/ts.rs b/crates/codegen/src/ts.rs index 4d31b3b..d335b29 100644 --- a/crates/codegen/src/ts.rs +++ b/crates/codegen/src/ts.rs @@ -63,7 +63,8 @@ impl Codegen { "write_file" => { format!("writeFile({}, {}){}\n", self.gen_ir(&args[0], false), self.gen_ir(&args[1], false), semicolon!()) }, "read" => { format!("read({}){}\n" , self.gen_ir(&args[0], false), semicolon!()) }, "read_file" => { format!("readFile({}){}\n" , self.gen_ir(&args[0], false), semicolon!()) } - "emit" => { format!("{}", self.gen_ir(&args[0], false).trim_start_matches('"').trim_end_matches('"')) }, + "emit" => { format!("{}", self.gen_ir(&args[0], false).trim_start_matches('"').trim_end_matches('"')) }, + "get" => { format!("{}[{}]", self.gen_ir(&args[0], false), self.gen_ir(&args[1], false)) }, _ => unreachable!(format!("Unknown intrinsic: {}", name)) // Shoul be handled by lowering } }, @@ -145,6 +146,17 @@ impl Codegen { } }, + IRKind::Vector { values } => { + format!( + "[{}]", + values + .iter() + .map(|value| self.gen_ir(value, false)) + .collect::>() + .join(", ") + ) + }, + #[allow(unreachable_patterns)] _ => { dbg!(ir); todo!() }, } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d8d14f9..5db1319 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1,12 +1,13 @@ use std::ops::Range; use parser::Expr; -const INTRINSICS: [&str; 5] = [ +const INTRINSICS: [&str; 6] = [ "write", "read", "write_file", "read_file", "emit", + "get", ]; #[derive(Debug, Clone)] @@ -47,7 +48,10 @@ pub enum IRKind { Case { cond: Box, cases: Vec<(Box, Box)>, default: Box }, Unary { op: String, right: Box }, Binary { op: String, left: Box, right: Box }, + Value { value: Value }, + Vector { values: Vec }, + Return { value: Box }, } @@ -102,6 +106,9 @@ impl std::fmt::Display for IRKind { IRKind::Value { ref value } => { write!(f, "{}", value) }, + IRKind::Vector { ref values } => { + write!(f, "[{}]", values.iter().map(|expr| expr.to_string()).collect::>().join(" ")) + }, IRKind::Return { ref value } => { write!(f, "(return {})", value) } @@ -402,6 +409,18 @@ pub fn expr_to_ir(expr: &Expr) -> (Option, Option) { Expr::Boolean(value) => (Some(IRKind::Value { value: Value::Boolean(*value) }), None), Expr::String(value) => (Some(IRKind::Value { value: Value::String(value.clone()) }), None), Expr::Identifier(value) => (Some(IRKind::Value { value: Value::Ident(value.clone()) }), None), + + Expr::Vector(values) => { + let mut lvalues = Vec::new(); + for value in values { + let value = expr_to_ir(&value.0); + if_err_return!(value.1); + + lvalues.push(value.0.unwrap()); + } + (Some(IRKind::Vector { values: lvalues }), None) + }, + // Probably will never happen because it is catched in parser Expr::Hole(start, end) => (None, Some(LoweringError { span: *start..*end, @@ -418,6 +437,10 @@ fn gen_type_hint(type_hint: &str) -> String { "bool" => "boolean".to_string(), "string" => "string".to_string(), "void" => "void".to_string(), + // TODO: Un-hardcode vector type + "vec_int" => "number[]".to_string(), + "vec_bool" => "boolean[]".to_string(), + "vec_str" => "string[]".to_string(), _ => { dbg!(type_hint); todo!() } } } diff --git a/crates/lexer/src/lib.rs b/crates/lexer/src/lib.rs index 30c074f..980543e 100644 --- a/crates/lexer/src/lib.rs +++ b/crates/lexer/src/lib.rs @@ -25,6 +25,7 @@ pub enum Token { Dot, Comma, Colon, SemiColon, OpenParen, CloseParen, + OpenBracket, CloseBracket, At, Hole, } @@ -69,8 +70,12 @@ impl std::fmt::Display for Token { Token::Comma => write!(f, ","), Token::Colon => write!(f, ":"), Token::SemiColon => write!(f, ";"), + Token::OpenParen => write!(f, "("), Token::CloseParen => write!(f, ")"), + Token::OpenBracket => write!(f, "["), + Token::CloseBracket => write!(f, "]"), + Token::At => write!(f, "@"), Token::Hole => write!(f, "_"), } @@ -112,6 +117,8 @@ pub fn lexer() -> impl Parser, Error = Simple> { just(';').to(Token::SemiColon), just('(').to(Token::OpenParen), just(')').to(Token::CloseParen), + just('[').to(Token::OpenBracket), + just(']').to(Token::CloseBracket), just('@').to(Token::At), just('_').to(Token::Hole), )); diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index b11fe6e..0c9ee5e 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -8,6 +8,8 @@ pub enum Expr { Int(i64), Float(f64), Boolean(bool), String(String), Identifier(String), + Vector(Vec>), + Unary { op: String, rhs: Box> }, Binary { lhs: Box>, op: String, rhs: Box> }, Call { name: Box>, args: Spanned>> }, @@ -67,11 +69,23 @@ fn expr_parser() -> impl Parser>, Error = Simple .separated_by(just(Token::Comma)) .allow_trailing(); + let vector = expr.clone() + .separated_by(just(Token::Comma)) + .allow_trailing() + .delimited_by( + just(Token::OpenBracket), + just(Token::CloseBracket), + ) + .map_with_span(|args, span| { + ( + Expr::Vector(args), + span, + ) + }); + let atom = literal .or(identifier.map(|(s, span)| (Expr::Identifier(s), span))) - // .or( - // expr.clone() - // .delimited_by(just(Token::OpenParen), just(Token::CloseParen))) + .or(vector) .labelled("atom"); let call = atom.clone() diff --git a/example/rule110.hz b/example/rule110.hz new file mode 100644 index 0000000..c1dbf02 --- /dev/null +++ b/example/rule110.hz @@ -0,0 +1,115 @@ +fun print_single (cell: bool): void = do + case cell of + | true -> @write("█"); + | else @write(" "); + end; +end; + +fun print_vec (state: vec_bool) (length: int) (curr: int): void = do + if curr == length then @write(""); else + do + @get(state, curr) |> print_single(_); + print_vec(state, length, curr + 1); + end; + end; +end; + +fun cell_merger (a: bool) (b: bool) (c: bool): bool = do + if a then + if b then + if c then + return false; + else + return true; + end; + else + if c then + return true; + else + return false; + end; + end; + else + if b then + if c then + return true; + else + return true; + end; + else + if c then + return true; + else + return false; + end; + end; + end; +end; + +fun next (state: vec_bool) (pointer: int): bool = do + case pointer of + | 0 -> do + let a: bool = false; + let b: bool = @get(state, 1); + let c: bool = @get(state, 2); + return cell_merger(a, b, c); + end; + | 1 -> do + let a: bool = @get(state, 0); + let b: bool = @get(state, 1); + let c: bool = @get(state, 2); + return cell_merger(a, b, c); + end; + | 2 -> do + let a: bool = @get(state, 1); + let b: bool = @get(state, 2); + let c: bool = @get(state, 3); + return cell_merger(a, b, c); + end; + | 3 -> do + let a: bool = @get(state, 2); + let b: bool = @get(state, 3); + let c: bool = @get(state, 4); + return cell_merger(a, b, c); + end; + | 4 -> do + let a: bool = @get(state, 3); + let b: bool = @get(state, 4); + let c: bool = @get(state, 5); + return cell_merger(a, b, c); + end; + | 5 -> do + return true; + end; + | else return false; + end; +end; + +fun iter (state: vec_bool) (for: int) (curr: int): void = do + if curr == for then + @write(""); + else + do + let next_state: vec_bool = [ + next(state, 0), + next(state, 1), + next(state, 2), + next(state, 3), + next(state, 4), + next(state, 5) + ]; + + print_vec(next_state, 6, 0); + @write("\n"); + iter(next_state, for, curr + 1); + end; + end; +end; + +fun main: void = do + let vec: vec_bool = [false, false, false, false, false, true]; + print_vec(vec, 6, 0); + @write("\n"); + + iter(vec, 20, 0); +end; \ No newline at end of file