diff --git a/shell.nix b/shell.nix new file mode 100644 index 000000000..5849e46a2 --- /dev/null +++ b/shell.nix @@ -0,0 +1,11 @@ +let + pkgs = import {}; +in + pkgs.stdenv.mkDerivation { + name = "nac3"; + buildInputs = [ + pkgs.libffi + pkgs.libxml2 + pkgs.llvm_8 + ]; + } diff --git a/src/main.rs b/src/main.rs index 7afecd720..1e36fa822 100644 --- a/src/main.rs +++ b/src/main.rs @@ -223,6 +223,56 @@ impl<'ctx> CodeGen<'ctx> { ast::ExpressionType::Number { value: ast::Number::Float { value } } => { Ok(self.context.f64_type().const_float(*value).into()) }, + ast::ExpressionType::List { elements } => { + if elements.len() == 0 { + return Err(self.compile_error(CompileErrorKind::Unsupported("Empty Array"))); + } + let elements: CompileResult> = elements.iter().map(|v| self.compile_expression(v)).collect(); + let elements = elements?; + let ty = elements[0].get_type(); + for v in elements.iter() { + if v.get_type() != ty { + return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)); + } + } + let len = self.context.i32_type().const_int(1 + elements.len() as u64, false); + let real_len = self.context.i32_type().const_int(elements.len() as u64, false); + let ptr = self.builder.build_array_alloca(ty, len, "tmparr"); + unsafe { + let len_ptr = self.builder.build_in_bounds_gep(ptr, + &[self.context.i32_type().const_int(0, false)], "len"); + self.builder.build_store(len_ptr, real_len); + } + for (i, v) in elements.iter().enumerate() { + let ptr = unsafe { + self.builder.build_in_bounds_gep(ptr, + &[self.context.i32_type().const_int(1 + i as u64, false)], + "gep") + }; + self.builder.build_store(ptr, *v); + } + Ok(ptr.into()) + }, + ast::ExpressionType::Subscript { a, b } => { + let a = self.compile_expression(a)?; + let b = self.compile_expression(b)?; + let a = match a.get_type() { + types::BasicTypeEnum::PointerType(_) => a.into_pointer_value(), + _ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)) + }; + let b = match b.get_type() { + types::BasicTypeEnum::IntType(_) => b.into_int_value().const_add( + self.context.i32_type().const_int(1, false) + ), + _ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)) + }; + // TODO: add range check + let ptr = unsafe { + self.builder.build_in_bounds_gep(a, + &[b], "gep") + }; + Ok(self.builder.build_load(ptr, "load").into()) + }, ast::ExpressionType::Identifier { name } => { match self.namespace.get(name) { Some(value) => Ok(self.builder.build_load(*value, name).into()), @@ -425,18 +475,47 @@ impl<'ctx> CodeGen<'ctx> { match &statement.node { Assign { targets, value } => { let value = self.compile_expression(value)?; + // TODO: Handle tuple for target in targets.iter() { self.set_source_location(target.location); - if let ast::ExpressionType::Identifier { name } = &target.node { - let builder = &self.builder; - let target = self.namespace.entry(name.clone()).or_insert_with( - || builder.build_alloca(value.get_type(), name)); - if target.get_type() != value.get_type().ptr_type(inkwell::AddressSpace::Generic) { - return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)); + let value_typ = value.get_type().ptr_type(inkwell::AddressSpace::Generic); + match &target.node { + ast::ExpressionType::Identifier { name } => { + let builder = &self.builder; + let target = self.namespace.entry(name.clone()).or_insert_with( + || builder.build_alloca(value.get_type(), name)); + if target.get_type() != value_typ { + return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)); + } + builder.build_store(*target, value); + }, + ast::ExpressionType::Subscript {a, b} => { + let a = self.compile_expression(a)?; + let b = self.compile_expression(b)?; + let a = match a.get_type() { + types::BasicTypeEnum::PointerType(_) => a.into_pointer_value(), + _ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)) + }; + let b = match b.get_type() { + types::BasicTypeEnum::IntType(_) => b.into_int_value().const_add( + self.context.i32_type().const_int(1, false) + ), + _ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)) + }; + // TODO: range check + let target = unsafe { + self.builder.build_in_bounds_gep(a, + &[b], "gep") + }; + if target.get_type() != value_typ { + return Err(self.compile_error(CompileErrorKind::IncompatibleTypes)); + } + self.builder.build_store(target, value); + }, + _ => { + return Err(self.compile_error(CompileErrorKind::Unsupported( + "assignment target must be an identifier"))); } - builder.build_store(*target, value); - } else { - return Err(self.compile_error(CompileErrorKind::Unsupported("assignment target must be an identifier"))) } } }, @@ -586,7 +665,7 @@ impl<'ctx> CodeGen<'ctx> { fn main() { Target::initialize_all(&InitializationConfig::default()); - let program = match fs::read_to_string("test.py") { + let program = match fs::read_to_string("test_arr.py") { Ok(program) => program, Err(err) => { println!("Cannot open input file: {}", err); return; } }; diff --git a/test_arr.py b/test_arr.py new file mode 100644 index 000000000..21b813f4f --- /dev/null +++ b/test_arr.py @@ -0,0 +1,9 @@ +def run() -> int32: + arr = [1, 2] + output(arr[0] + arr[1]) + + arr2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + arr2[output(1)][0] = 3 + arr3 = [arr, arr2[0], arr2[1], arr2[2]] + output(arr3[0][0] + arr2[1][0] + arr2[2][0]) + return 0