diff --git a/Cargo.lock b/Cargo.lock index 9f6ace4..3d8ea98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -410,6 +410,7 @@ dependencies = [ "logos", "salsa-2022", "tracing", + "unescaper", ] [[package]] @@ -1731,6 +1732,15 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "unescaper" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f0f68e58d297ba8b22b8b5a96a87b863ba6bb46aaf51e19a4b02c5a6dd5b7f" +dependencies = [ + "thiserror", +] + [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/crates/concrete_ast/src/expressions.rs b/crates/concrete_ast/src/expressions.rs index 12f8752..cdecc70 100644 --- a/crates/concrete_ast/src/expressions.rs +++ b/crates/concrete_ast/src/expressions.rs @@ -18,8 +18,8 @@ pub enum Expression { pub enum ValueExpr { ConstBool(bool), ConstChar(char), - ConstInt(u64), - ConstFloat(()), + ConstInt(u128), + ConstFloat(String), ConstStr(String), Path(PathOp), Deref(PathOp), diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 0db203f..cd4da68 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -18,7 +18,10 @@ use melior::{ cf, func, memref, }, ir::{ - attribute::{FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, TypeAttribute}, + attribute::{ + FlatSymbolRefAttribute, FloatAttribute, IntegerAttribute, StringAttribute, + TypeAttribute, + }, r#type::{FunctionType, IntegerType, MemRefType}, Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, Value, ValueLike, @@ -133,6 +136,7 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { "u32" | "i32" => IntegerType::new(context, 32).into(), "u16" | "i16" => IntegerType::new(context, 16).into(), "u8" | "i8" => IntegerType::new(context, 8).into(), + "char" => IntegerType::new(context, 32).into(), "f32" => Type::float32(context), "f64" => Type::float64(context), "bool" => IntegerType::new(context, 1).into(), @@ -813,7 +817,22 @@ fn compile_value_expr<'ctx, 'parent: 'ctx>( .result(0)? .into()) } - ValueExpr::ConstFloat(_) => todo!(), + ValueExpr::ConstFloat(value) => { + let float_type = if let Some(type_info) = type_info { + scope_ctx.resolve_type_spec(context, type_info)? + } else { + Type::float64(context) + }; + let value = FloatAttribute::new( + context, + value.parse().expect("failed to parse float"), + float_type, + ); + Ok(block + .append_operation(arith::constant(context, value.into(), location)) + .result(0)? + .into()) + } ValueExpr::ConstStr(_) => todo!(), ValueExpr::Path(value) => { compile_path_op(session, context, scope_ctx, _helper, block, value) diff --git a/crates/concrete_driver/tests/programs.rs b/crates/concrete_driver/tests/programs.rs index fecc2f3..660d9bc 100644 --- a/crates/concrete_driver/tests/programs.rs +++ b/crates/concrete_driver/tests/programs.rs @@ -132,26 +132,58 @@ fn test_import() { } #[test] -fn test_reference() { +fn test_floats() { let source = r#" - mod Simple { - fn main(argc: i64) -> i64 { - let x: i64 = argc; - return references(x) + dereference(&x); - } + mod Simple { + fn main() -> i64 { + let a: f32 = my_f32(2.0, 4.0); + let b: f64 = my_f64(2.0, 4.0); + return 1; + } - fn dereference(a: &i64) -> i64 { - return *a; - } + fn my_f32(x: f32, y: f32) -> f32 { + let literal: f32 = 2.0; + let literal2: f32 = 2.001; + let literal3: f32 = 0.1; + return x + y + literal2 + literal3; + } - fn references(a: i64) -> i64 { - let x: i64 = a; - let y: &i64 = &x; - return *y; - } + fn my_f64(x: f64, y: f64) -> f64 { + let literal: f64 = 2.0; + let literal2: f64 = 2.002; + let literal3: f64 = 0.02; + return x + y + literal2 + literal3; } + } "#; + let result = compile_program(source, "floats", false).expect("failed to compile"); + + let output = run_program(&result.binary_file).expect("failed to run"); + let code = output.status.code().unwrap(); + assert_eq!(code, 1); +} + +#[test] +fn test_reference() { + let source = r#" + mod Simple { + fn main(argc: i64) -> i64 { + let x: i64 = argc; + return references(x) + dereference(&x); + } + + fn dereference(a: &i64) -> i64 { + return *a; + } + + fn references(a: i64) -> i64 { + let x: i64 = a; + let y: &i64 = &x; + return *y; + } + } + "#; let result = compile_program(source, "references", false).expect("failed to compile"); let output = run_program(&result.binary_file).expect("failed to run"); diff --git a/crates/concrete_parser/Cargo.toml b/crates/concrete_parser/Cargo.toml index 239eba6..f0422e6 100644 --- a/crates/concrete_parser/Cargo.toml +++ b/crates/concrete_parser/Cargo.toml @@ -13,6 +13,7 @@ concrete_ast = { path = "../concrete_ast"} salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022" } ariadne = { version = "0.4.0", features = ["auto-color"] } itertools = "0.12.0" +unescaper = "0.1.3" [build-dependencies] lalrpop = "0.20.0" diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index bc3c1ee..0f91c54 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -30,8 +30,10 @@ extern { // literals "identifier" => Token::Identifier(), - "integer" => Token::Integer(), + "integer" => Token::Integer(), + "float" => Token::Float(), "string" => Token::String(), + "char" => Token::Char(), "boolean" => Token::Boolean(), // Other @@ -150,7 +152,7 @@ pub(crate) TypeSpec: ast::types::TypeSpec = { }, "[" )> "]" => ast::types::TypeSpec::Array { of_type: Box::new(of_type), - size, + size: size.map(|x| x.try_into().expect("size is too big")), is_ref, span: Span::new(lo, hi), } @@ -355,8 +357,10 @@ pub UnaryOp: ast::expressions::UnaryOp = { pub(crate) ValueExpr: ast::expressions::ValueExpr = { <"integer"> => ast::expressions::ValueExpr::ConstInt(<>), + <"float"> => ast::expressions::ValueExpr::ConstFloat(<>), <"boolean"> => ast::expressions::ValueExpr::ConstBool(<>), <"string"> => ast::expressions::ValueExpr::ConstStr(<>), + <"char"> => ast::expressions::ValueExpr::ConstChar(<>), => ast::expressions::ValueExpr::Path(<>), "*" => ast::expressions::ValueExpr::Deref(<>), => ast::expressions::ValueExpr::AsRef { diff --git a/crates/concrete_parser/src/lib.rs b/crates/concrete_parser/src/lib.rs index d0b4e1b..52c0a51 100644 --- a/crates/concrete_parser/src/lib.rs +++ b/crates/concrete_parser/src/lib.rs @@ -89,7 +89,7 @@ mod ModuleName { "##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -104,7 +104,7 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -116,7 +116,7 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -128,6 +128,6 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } } diff --git a/crates/concrete_parser/src/tokens.rs b/crates/concrete_parser/src/tokens.rs index 316a74d..1781db7 100644 --- a/crates/concrete_parser/src/tokens.rs +++ b/crates/concrete_parser/src/tokens.rs @@ -57,12 +57,25 @@ pub enum Token { Identifier(String), // Literals - #[regex(r"\d+", |lex| lex.slice().parse::().unwrap())] - Integer(u64), - #[regex(r#""(?:[^"]|\\")*""#, |lex| lex.slice().to_string())] + #[regex(r"\d+", |lex| lex.slice().parse::().unwrap(), priority = 2)] + Integer(u128), + #[regex(r"\d+\.\d+", |lex| lex.slice().to_string(), priority = 1)] + Float(String), + #[regex(r#""(?:[^"]|\\")*""#, |lex| { + let slice = lex.slice(); + let len = slice.len(); + unescaper::unescape(&slice[1..(len-1)]).expect("failed to unescape string") + })] String(String), #[regex(r"(true|false)", |lex| lex.slice().parse::().unwrap())] Boolean(bool), + #[regex(r#"'(?:[^']|\\')*'"#, |lex| { + let slice = lex.slice(); + let len = slice.len(); + let real_char = unescaper::unescape(&slice[1..(len-1)]).expect("failed to unescape char").to_string(); + real_char.chars().next().unwrap() + })] + Char(char), #[token("(")] LeftParen, diff --git a/examples/chars.con b/examples/chars.con new file mode 100644 index 0000000..cb878d5 --- /dev/null +++ b/examples/chars.con @@ -0,0 +1,13 @@ + mod Simple { + fn main() -> i64 { + let a: char = hello_chars('\t'); + return 1; + } + + fn hello_chars(a: char) -> char { + let x: char = 'b'; + let newline: char = '\n'; + + return x + newline + a; + } +} diff --git a/examples/floats.con b/examples/floats.con new file mode 100644 index 0000000..bcfca6f --- /dev/null +++ b/examples/floats.con @@ -0,0 +1,21 @@ + mod Simple { + fn main() -> i64 { + let a: f32 = my_f32(2.0, 4.0); + let b: f64 = my_f64(2.0, 4.0); + return 1; + } + + fn my_f32(x: f32, y: f32) -> f32 { + let literal: f32 = 2.0; + let literal2: f32 = 2.001; + let literal3: f32 = 0.1; + return x + y + literal2 + literal3; + } + + fn my_f64(x: f64, y: f64) -> f64 { + let literal: f64 = 2.0; + let literal2: f64 = 2.002; + let literal3: f64 = 0.02; + return x + y + literal2 + literal3; + } +}